diff --git a/.eslintignore b/.eslintignore index 5d521d54e4..dcaf180252 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,6 +8,7 @@ # Ignore build folders /node_modules/ /public/ +/build/ # Ignore test files inside /src/components src/__tests__/** @@ -19,14 +20,10 @@ src/components/BMDashboard/_tests_/BMDashboard.test.jsx src/components/Login/ForgotPassword.test.jsx src/components/Login/LoginPage.test.js src/components/PermissionsManagement/PermissionsManagement.test.js -src/components/Reports/PeopleReport/components/PeopleTasksPieChart.test.jsx # Ignore folders in /src -src/actions/** src/components/Badge/** -src/components/common/** src/components/Dashboard/** -src/components/EmailSubscribeForm/** src/components/Projects/** src/components/SummaryManagement/** src/components/TaskEditSuggestions/** diff --git a/src/actions/__tests__/allTeamsAction.js.test.js b/src/actions/__tests__/allTeamsAction.js.test.js index 813c0a09bd..bc25c056ff 100644 --- a/src/actions/__tests__/allTeamsAction.js.test.js +++ b/src/actions/__tests__/allTeamsAction.js.test.js @@ -1,10 +1,39 @@ // Import the necessary action creators and constants from the respective files -import { teamMembersFectchACtion, userTeamsUpdateAction, addNewTeam, teamsDeleteAction, updateTeamAction, teamUsersFetchAction, teamUsersFetchCompleteAction, teamUsersFetchErrorAction, teamMemberDeleteAction, teamMemberAddAction, updateVisibilityAction, fetchAllTeamCodeSucess, fetchAllTeamCodeFailure, getAllUserTeams, postNewTeam, deleteTeam } from '../allTeamsAction'; -import { RECEIVE_ALL_USER_TEAMS, USER_TEAMS_UPDATE, ADD_NEW_TEAM, TEAMS_DELETE, UPDATE_TEAM, FETCH_TEAM_USERS_START, RECEIVE_TEAM_USERS, FETCH_TEAM_USERS_ERROR, TEAM_MEMBER_DELETE, TEAM_MEMBER_ADD, UPDATE_TEAM_MEMBER_VISIBILITY, FETCH_ALL_TEAM_CODE_SUCCESS, FETCH_ALL_TEAM_CODE_FAILURE } from '../../constants/allTeamsConstants'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; +import { + RECEIVE_ALL_USER_TEAMS, + USER_TEAMS_UPDATE, + ADD_NEW_TEAM, + TEAMS_DELETE, + UPDATE_TEAM, + FETCH_TEAM_USERS_START, + RECEIVE_TEAM_USERS, + FETCH_TEAM_USERS_ERROR, + TEAM_MEMBER_DELETE, + TEAM_MEMBER_ADD, + UPDATE_TEAM_MEMBER_VISIBILITY, + FETCH_ALL_TEAM_CODE_SUCCESS, +} from '../../constants/allTeamsConstants'; +import { + teamMembersFectchACtion, + userTeamsUpdateAction, + addNewTeam, + teamsDeleteAction, + updateTeamAction, + teamUsersFetchAction, + teamUsersFetchCompleteAction, + teamUsersFetchErrorAction, + teamMemberDeleteAction, + teamMemberAddAction, + updateVisibilityAction, + fetchAllTeamCodeSucess, + getAllUserTeams, + postNewTeam, + deleteTeam, +} from '../allTeamsAction'; import { ENDPOINTS } from '../../utils/URL'; const middlewares = [thunk]; @@ -16,7 +45,10 @@ describe('teamMembersFectchACtion', () => { // Test case for creating an action to set all user teams it('should create an action to set all user teams', () => { // Define the payload for the action - const payload = [{ id: 1, name: 'Team 1' }, { id: 2, name: 'Team 2' }]; + const payload = [ + { id: 1, name: 'Team 1' }, + { id: 2, name: 'Team 2' }, + ]; // Define the expected action object const expectedAction = { type: RECEIVE_ALL_USER_TEAMS, @@ -109,7 +141,10 @@ describe('teamUsersFetchAction', () => { // Describe block for the teamUsersFetchCompleteAction tests describe('teamUsersFetchCompleteAction', () => { it('should create an action to set team users', () => { - const payload = [{ id: 1, name: 'User 1' }, { id: 2, name: 'User 2' }]; + const payload = [ + { id: 1, name: 'User 1' }, + { id: 2, name: 'User 2' }, + ]; const expectedAction = { type: RECEIVE_TEAM_USERS, payload, @@ -198,18 +233,18 @@ describe('fetchAllTeamCodeSucess', () => { }); }); - // Describe block for the getAllUserTeams tests describe('getAllUserTeams', () => { // Test case for fetching all user teams it('should fetch all user teams and dispatch RECEIVE_ALL_USER_TEAMS action', async () => { // Mock the API response - const responseData = [{ id: 1, name: 'Team 1' }, { id: 2, name: 'Team 2' }]; + const responseData = [ + { id: 1, name: 'Team 1' }, + { id: 2, name: 'Team 2' }, + ]; mock.onGet(ENDPOINTS.TEAM).reply(200, responseData); - const expectedActions = [ - { type: RECEIVE_ALL_USER_TEAMS, payload: responseData }, - ]; + const expectedActions = [{ type: RECEIVE_ALL_USER_TEAMS, payload: responseData }]; const store = mockStore({}); await store.dispatch(getAllUserTeams()); @@ -225,9 +260,7 @@ describe('postNewTeam', () => { const responseData = { id: 3, name: 'New Team' }; mock.onPost(ENDPOINTS.TEAM).reply(200, responseData); - const expectedActions = [ - { type: ADD_NEW_TEAM, payload: responseData, status: true }, - ]; + const expectedActions = [{ type: ADD_NEW_TEAM, payload: responseData, status: true }]; const store = mockStore({}); await store.dispatch(postNewTeam('New Team', true)); @@ -243,13 +276,10 @@ describe('deleteTeam', () => { const teamId = 1; mock.onDelete(ENDPOINTS.TEAM_DATA(teamId)).reply(200); - const expectedActions = [ - { type: TEAMS_DELETE, team: teamId }, - ]; + const expectedActions = [{ type: TEAMS_DELETE, team: teamId }]; const store = mockStore({}); await store.dispatch(deleteTeam(teamId)); expect(store.getActions()).toEqual(expectedActions); }); }); - diff --git a/src/actions/__tests__/authActions.js.test.js b/src/actions/__tests__/authActions.js.test.js index ea65be2eb6..9bdf5a6a28 100644 --- a/src/actions/__tests__/authActions.js.test.js +++ b/src/actions/__tests__/authActions.js.test.js @@ -1,18 +1,17 @@ import configureMockStore from 'redux-mock-store'; // Import mock store configuration import thunk from 'redux-thunk'; // Import thunk middleware +import jwtDecode from 'jwt-decode'; // Import jwtDecode +import axios from 'axios'; // Import axios import httpService from '../../services/httpService'; // Import httpService import { loginUser, // Import loginUser action loginBMUser, // Import loginBMUser action - getHeaderData, // Import getHeaderData action logoutUser, // Import logoutUser action refreshToken as refreshUserToken, // Import refreshToken action and rename it to avoid conflict setCurrentUser, // Import setCurrentUser action setHeaderData, // Import setHeaderData action } from '../authActions'; // Import actions from authActions -import { SET_CURRENT_USER, GET_ERRORS, SET_HEADER_DATA } from '../../constants/auth'; // Import constants -import jwtDecode from 'jwt-decode'; // Import jwtDecode -import axios from 'axios'; // Import axios +import { SET_CURRENT_USER, SET_HEADER_DATA } from '../../constants/auth'; // Import constants const middlewares = [thunk]; // Define middlewares const mockStore = configureMockStore(middlewares); // Create mock store with middlewares @@ -106,5 +105,4 @@ describe('authActions', () => { expect(setHeaderData(data)).toEqual(expectedAction); // Assert the action }); - }); diff --git a/src/actions/__tests__/blueSquareEmailBCCAction.js.test.js b/src/actions/__tests__/blueSquareEmailBCCAction.js.test.js index 7cb5d4f49b..92bb167761 100644 --- a/src/actions/__tests__/blueSquareEmailBCCAction.js.test.js +++ b/src/actions/__tests__/blueSquareEmailBCCAction.js.test.js @@ -2,7 +2,10 @@ import axios from 'axios'; // Import axios for making HTTP requests import configureMockStore from 'redux-mock-store'; // Import redux-mock-store for creating a mock store import thunk from 'redux-thunk'; // Import redux-thunk for handling asynchronous actions import * as types from '../../constants/BluequareEmailBccConstants'; // Import the action type constants -import { setBlueSquareEmailAssignement, deleteBlueSquareEmailAssignement } from '../blueSquareEmailBCCAction'; // Import the action creator +import { + setBlueSquareEmailAssignement, + deleteBlueSquareEmailAssignement, +} from '../blueSquareEmailBCCAction'; // Import the action creator // Mock axios to control its behavior in tests jest.mock('axios'); diff --git a/src/actions/__tests__/dashboardActions.test.js b/src/actions/__tests__/dashboardActions.test.js index 9a99f2e97b..941ea20324 100644 --- a/src/actions/__tests__/dashboardActions.test.js +++ b/src/actions/__tests__/dashboardActions.test.js @@ -1,7 +1,5 @@ -import { - incrementDashboardTaskCount, - INCREMENT_DASHBOARD_TASK_COUNT, -} from '../dashboardActions'; +import { toast } from 'react-toastify'; +import { incrementDashboardTaskCount, INCREMENT_DASHBOARD_TASK_COUNT } from '../dashboardActions'; describe('incrementDashboardTaskCount action creator', () => { it('should create an action to increment the dashboard task count', () => { @@ -12,12 +10,12 @@ describe('incrementDashboardTaskCount action creator', () => { }; // Spy on console.log - console.log = jest.fn(); + toast.info = jest.fn(); const action = incrementDashboardTaskCount(taskId); expect(action).toEqual(expectedAction); - expect(console.log).toHaveBeenCalledWith( + expect(toast.info).toHaveBeenCalledWith( `Dispatching incrementDashboardTaskCount for task ID: ${taskId}`, ); }); diff --git a/src/actions/__tests__/followUpActions.test.js b/src/actions/__tests__/followUpActions.test.js index 38a13c9ef0..78af63d18e 100644 --- a/src/actions/__tests__/followUpActions.test.js +++ b/src/actions/__tests__/followUpActions.test.js @@ -57,7 +57,7 @@ describe('followUpActions', () => { expect(axios.post).toHaveBeenCalledWith( ENDPOINTS.SET_USER_FOLLOWUP(userId, taskId), - updateData + updateData, ); expect(dispatch).toHaveBeenCalledWith({ type: types.SET_FOLLOWUP, diff --git a/src/actions/__tests__/index.js.test.js b/src/actions/__tests__/index.js.test.js index c35b243128..c9122832d2 100644 --- a/src/actions/__tests__/index.js.test.js +++ b/src/actions/__tests__/index.js.test.js @@ -1,8 +1,27 @@ -import { clearUserProfile, getUserTeamMembers, getUserProjectMembers, getDashboardData, getActionItems, getNotifications, getAllProjects, getProjectById, getProjectsByUser, getProjectMembership, getAllTeams, getTeamById, getTeamMembership, getAllTimeEntries, getTimeEntryForSpecifiedPeriod, postTimeEntry, getTimeEntryByProjectSpecifiedPeriod, getTimeEntryForOverDate } from '../index'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import httpService from '../../services/httpService'; import axios from 'axios'; // Add this import +import httpService from '../../services/httpService'; +import { + clearUserProfile, + getUserTeamMembers, + getUserProjectMembers, + getDashboardData, + getActionItems, + getNotifications, + getAllProjects, + getProjectById, + getProjectsByUser, + getProjectMembership, + getAllTeams, + getTeamById, + getTeamMembership, + getAllTimeEntries, + getTimeEntryForSpecifiedPeriod, + postTimeEntry, + getTimeEntryByProjectSpecifiedPeriod, + getTimeEntryForOverDate, +} from '../index'; const middlewares = [thunk]; const mockStore = configureMockStore(middlewares); @@ -25,9 +44,7 @@ describe('getUserTeamMembers action', () => { const mockData = { teamMembers: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_USER_TEAM_MEMBERS', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_USER_TEAM_MEMBERS', payload: mockData }]; const store = mockStore({}); @@ -44,9 +61,7 @@ describe('getUserProjectMembers action', () => { const mockData = { projectMembers: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_USER_PROJECT_MEMBERS', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_USER_PROJECT_MEMBERS', payload: mockData }]; const store = mockStore({}); @@ -63,9 +78,7 @@ describe('getDashboardData action', () => { const mockData = { dashboardData: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_DASHBOARD_DATA', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_DASHBOARD_DATA', payload: mockData }]; const store = mockStore({}); @@ -82,9 +95,7 @@ describe('getActionItems action', () => { const mockData = { actionItems: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_ACTION_ITEMS', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_ACTION_ITEMS', payload: mockData }]; const store = mockStore({}); @@ -101,9 +112,7 @@ describe('getNotifications action', () => { const mockData = { notifications: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_NOTIFICATIONS', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_NOTIFICATIONS', payload: mockData }]; const store = mockStore({}); @@ -119,9 +128,7 @@ describe('getAllProjects action', () => { const mockData = { projects: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_ALL_PROJECTS', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_ALL_PROJECTS', payload: mockData }]; const store = mockStore({}); @@ -138,9 +145,7 @@ describe('getProjectById action', () => { const mockData = { project: {} }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_PROJECT_BY_ID', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_PROJECT_BY_ID', payload: mockData }]; const store = mockStore({}); @@ -157,9 +162,7 @@ describe('getProjectsByUser action', () => { const mockData = { projects: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_PROJECTS_BY_USER', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_PROJECTS_BY_USER', payload: mockData }]; const store = mockStore({}); @@ -176,9 +179,7 @@ describe('getProjectMembership action', () => { const mockData = { members: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_PROJECT_MEMBERSHIP', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_PROJECT_MEMBERSHIP', payload: mockData }]; const store = mockStore({}); @@ -194,9 +195,7 @@ describe('getAllTeams action', () => { const mockData = { teams: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_ALL_TEAMS', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_ALL_TEAMS', payload: mockData }]; const store = mockStore({}); @@ -213,9 +212,7 @@ describe('getTeamById action', () => { const mockData = { team: {} }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_TEAM_BY_ID', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_TEAM_BY_ID', payload: mockData }]; const store = mockStore({}); @@ -232,9 +229,7 @@ describe('getTeamMembership action', () => { const mockData = { members: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_TEAM_MEMBERSHIP', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_TEAM_MEMBERSHIP', payload: mockData }]; const store = mockStore({}); @@ -250,9 +245,7 @@ describe('getAllTimeEntries action', () => { const mockData = { timeEntries: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_ALL_TIME_ENTRIES', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_ALL_TIME_ENTRIES', payload: mockData }]; const store = mockStore({}); @@ -271,9 +264,7 @@ describe('getTimeEntryForSpecifiedPeriod action', () => { const mockData = { timeEntries: [] }; httpService.get.mockResolvedValue({ data: mockData }); - const expectedActions = [ - { type: 'GET_TIME_ENTRY_FOR_SPECIFIED_PERIOD', payload: mockData }, - ]; + const expectedActions = [{ type: 'GET_TIME_ENTRY_FOR_SPECIFIED_PERIOD', payload: mockData }]; const store = mockStore({}); @@ -290,9 +281,7 @@ describe('postTimeEntry action', () => { const mockResponse = { data: { id: '909' } }; httpService.post.mockResolvedValue(mockResponse); - const expectedActions = [ - { type: 'REQUEST_SUCCEEDED', payload: mockResponse }, - ]; + const expectedActions = [{ type: 'REQUEST_SUCCEEDED', payload: mockResponse }]; const store = mockStore({}); @@ -317,9 +306,11 @@ describe('getTimeEntryByProjectSpecifiedPeriod action', () => { const store = mockStore({}); - return store.dispatch(getTimeEntryByProjectSpecifiedPeriod(projectId, fromDate, toDate)).then(() => { - expect(store.getActions()).toEqual(expectedActions); - }); + return store + .dispatch(getTimeEntryByProjectSpecifiedPeriod(projectId, fromDate, toDate)) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); }); }); diff --git a/src/actions/__tests__/roleAction.test.js b/src/actions/__tests__/roleAction.test.js index 2367742977..1df2e97018 100644 --- a/src/actions/__tests__/roleAction.test.js +++ b/src/actions/__tests__/roleAction.test.js @@ -92,10 +92,7 @@ describe('Role Actions', () => { const response = await actions.updateRole(roleId, updatedRole)(dispatch); - expect(axios.patch).toHaveBeenCalledWith( - ENDPOINTS.ROLES_BY_ID(roleId), - updatedRole - ); + expect(axios.patch).toHaveBeenCalledWith(ENDPOINTS.ROLES_BY_ID(roleId), updatedRole); expect(dispatch).toHaveBeenCalledWith(actions.modifyRole(updatedRole)); expect(response).toBe(0); }); diff --git a/src/actions/__tests__/taskNotification.js.test.js b/src/actions/__tests__/taskNotification.js.test.js index 9ced341469..c1434ac595 100644 --- a/src/actions/__tests__/taskNotification.js.test.js +++ b/src/actions/__tests__/taskNotification.js.test.js @@ -1,6 +1,8 @@ import axios from 'axios'; // Import axios for mocking +import { toast } from 'react-toastify'; import { createOrUpdateTaskNotificationHTTP } from '../taskNotification'; // Import the function to be tested -import { ENDPOINTS } from '../../utils/URL'; // Import the endpoints +import { ENDPOINTS } from '../../utils/URL'; +// Import the endpoints jest.mock('axios'); // Mock axios describe('createOrUpdateTaskNotificationHTTP', () => { it('should post the correct payload to the endpoint', async () => { @@ -19,8 +21,10 @@ describe('createOrUpdateTaskNotificationHTTP', () => { const userIds = ['user1', 'user2']; const errorMessage = 'Network Error'; axios.post.mockRejectedValue(new Error(errorMessage)); - console.log = jest.fn(); + toast.info = jest.fn(); await createOrUpdateTaskNotificationHTTP(taskId, oldTask, userIds); - expect(console.log).toHaveBeenCalledWith(`Error on create or update task notification with error: Error: ${errorMessage}`); + expect(toast.info).toHaveBeenCalledWith( + `Error on create or update task notification with error: Error: ${errorMessage}`, + ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/__tests__/teams.js.test.js b/src/actions/__tests__/teams.js.test.js index 53efd32198..5583586786 100644 --- a/src/actions/__tests__/teams.js.test.js +++ b/src/actions/__tests__/teams.js.test.js @@ -1,3 +1,4 @@ +import axios from 'axios'; // Import axios import { setTeamDetail, getUserTeamMembers, @@ -8,7 +9,6 @@ import { import { GET_TEAM_BY_ID } from '../../constants/team'; import httpService from '../../services/httpService'; import { ENDPOINTS } from '../../utils/URL'; -import axios from 'axios'; // Import axios jest.mock('../../services/httpService'); jest.mock('axios'); // Mock axios @@ -126,7 +126,7 @@ describe('fetchAllManagingTeams', () => { .mockResolvedValueOnce(mockTeamMembersResponse) // Mock the HTTP GET request for team members of team1 .mockResolvedValueOnce(mockTeamMembersResponse) // Mock the HTTP GET request for team members of team2 .mockResolvedValueOnce(mockTimeEntriesResponse) // Mock the HTTP GET request for time entries of member1 - .mockResolvedValueOnce(mockTimeEntriesResponse) // Mock the HTTP GET request for time entries of member2 + .mockResolvedValueOnce(mockTimeEntriesResponse); // Mock the HTTP GET request for time entries of member2 const dispatch = jest.fn(); // Create a mock dispatch function diff --git a/src/actions/__tests__/timeEntries.js.test.js b/src/actions/__tests__/timeEntries.js.test.js index 0cf0a59b89..116a2b80ca 100644 --- a/src/actions/__tests__/timeEntries.js.test.js +++ b/src/actions/__tests__/timeEntries.js.test.js @@ -1,8 +1,9 @@ // Import the functions to test +import moment from 'moment-timezone'; // Import moment-timezone +import axios from 'axios'; import { setTimeEntriesForPeriod, setTimeEntriesForWeek, - updateTimeEntries, getTimeEntriesForWeek, deleteTimeEntry, editTimeEntry, @@ -15,9 +16,7 @@ import { GET_TIME_ENTRIES_PERIOD, GET_TIME_ENTRIES_WEEK } from '../../constants/ // Import ENDPOINTS import { ENDPOINTS } from '../../utils/URL'; // Import moment for date manipulation -import moment from 'moment-timezone'; // Import moment-timezone // Mock axios for HTTP requests -import axios from 'axios'; // Mock axios module jest.mock('axios'); @@ -29,6 +28,7 @@ describe('timeEntries action creators', () => { }); afterAll(() => { + // eslint-disable-next-line no-console console.error.mockRestore(); }); @@ -189,53 +189,85 @@ describe('timeEntries action creators', () => { it('should return the last entry date', async () => { const dispatchMock = jest.fn(); // Mock dispatch function const userId = '123'; // Sample user ID - const fromDate = moment().subtract(2, 'weeks').toISOString(); // Sample from date + const fromDate = moment() + .subtract(2, 'weeks') + .toISOString(); // Sample from date const toDate = moment().toISOString(); // Sample to date - const formattedToDate = moment(toDate).endOf('day').format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate + const formattedToDate = moment(toDate) + .endOf('day') + .format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate const timeEntries = [ - { dateOfWork: moment().subtract(1, 'days').toISOString(), createdDateTime: moment().subtract(1, 'days').toISOString() }, - { dateOfWork: moment().subtract(2, 'days').toISOString(), createdDateTime: moment().subtract(2, 'days').toISOString() }, - ]; // Sample time entries + { + dateOfWork: moment() + .subtract(1, 'days') + .toISOString(), + createdDateTime: moment() + .subtract(1, 'days') + .toISOString(), + }, + { + dateOfWork: moment() + .subtract(2, 'days') + .toISOString(), + createdDateTime: moment() + .subtract(2, 'days') + .toISOString(), + }, + ]; // Sample time entries axios.get.mockResolvedValue({ data: timeEntries }); // Mock axios get response const result = await getTimeEndDateEntriesByPeriod(userId, fromDate, toDate)(dispatchMock); // Call getTimeEndDateEntriesByPeriod - + // Verify the result is the formatted date of the last entry expect(result).toBe(timeEntries[0].createdDateTime); // Verify axios.get was called with the correct URL - expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate)); + expect(axios.get).toHaveBeenCalledWith( + ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate), + ); }); it('should return "N/A" if no entries are found', async () => { const dispatchMock = jest.fn(); // Mock dispatch function const userId = '123'; // Sample user ID - const fromDate = moment().subtract(2, 'weeks').toISOString(); // Sample from date + const fromDate = moment() + .subtract(2, 'weeks') + .toISOString(); // Sample from date const toDate = moment().toISOString(); // Sample to date - const formattedToDate = moment(toDate).endOf('day').format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate + const formattedToDate = moment(toDate) + .endOf('day') + .format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate axios.get.mockResolvedValue({ data: [] }); // Mock axios get response with no data const result = await getTimeEndDateEntriesByPeriod(userId, fromDate, toDate)(dispatchMock); // Call getTimeEndDateEntriesByPeriod // Verify the result is "N/A" - expect(result).toBe("N/A"); + expect(result).toBe('N/A'); // Verify axios.get was called with the correct URL - expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate)); + expect(axios.get).toHaveBeenCalledWith( + ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate), + ); }); it('should handle errors and return "N/A"', async () => { const dispatchMock = jest.fn(); // Mock dispatch function const userId = '123'; // Sample user ID - const fromDate = moment().subtract(2, 'weeks').toISOString(); // Sample from date + const fromDate = moment() + .subtract(2, 'weeks') + .toISOString(); // Sample from date const toDate = moment().toISOString(); // Sample to date - const formattedToDate = moment(toDate).endOf('day').format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate + const formattedToDate = moment(toDate) + .endOf('day') + .format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate axios.get.mockRejectedValue(new Error('Request failed')); // Mock axios get error response const result = await getTimeEndDateEntriesByPeriod(userId, fromDate, toDate)(dispatchMock); // Call getTimeEndDateEntriesByPeriod // Verify the result is "N/A" - expect(result).toBe("N/A"); + expect(result).toBe('N/A'); // Verify axios.get was called with the correct URL - expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate)); + expect(axios.get).toHaveBeenCalledWith( + ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate), + ); }); }); @@ -244,12 +276,24 @@ describe('timeEntries action creators', () => { it('should dispatch setTimeEntriesForPeriod with filtered and sorted entries', async () => { const dispatchMock = jest.fn(); // Mock dispatch function const userId = '123'; // Sample user ID - const fromDate = moment().subtract(2, 'weeks').toISOString(); // Sample from date + const fromDate = moment() + .subtract(2, 'weeks') + .toISOString(); // Sample from date const toDate = moment().toISOString(); // Sample to date - const formattedToDate = moment(toDate).endOf('day').format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate + const formattedToDate = moment(toDate) + .endOf('day') + .format('YYYY-MM-DDTHH:mm:ss'); // Adjusted toDate const timeEntries = [ - { dateOfWork: moment().subtract(1, 'days').toISOString() }, - { dateOfWork: moment().subtract(2, 'days').toISOString() }, + { + dateOfWork: moment() + .subtract(1, 'days') + .toISOString(), + }, + { + dateOfWork: moment() + .subtract(2, 'days') + .toISOString(), + }, ]; // Sample time entries axios.get.mockResolvedValue({ data: timeEntries }); // Mock axios get response @@ -258,10 +302,14 @@ describe('timeEntries action creators', () => { // Verify dispatchMock was called with setTimeEntriesForPeriod and filtered entries expect(dispatchMock).toHaveBeenCalledWith({ type: GET_TIME_ENTRIES_PERIOD, - payload: timeEntries.sort((a, b) => moment(b.dateOfWork).valueOf() - moment(a.dateOfWork).valueOf()), + payload: timeEntries.sort( + (a, b) => moment(b.dateOfWork).valueOf() - moment(a.dateOfWork).valueOf(), + ), }); // Verify axios.get was called with the correct URL - expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate)); + expect(axios.get).toHaveBeenCalledWith( + ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, formattedToDate), + ); }); }); @@ -271,11 +319,27 @@ describe('timeEntries action creators', () => { const dispatchMock = jest.fn(); // Mock dispatch function const userId = '123'; // Sample user ID const offset = 1; // Sample offset - const fromDate = moment().tz('America/Los_Angeles').startOf('week').subtract(offset, 'weeks').format('YYYY-MM-DDTHH:mm:ss'); - const toDate = moment().tz('America/Los_Angeles').endOf('week').subtract(offset, 'weeks').format('YYYY-MM-DDTHH:mm:ss'); + const fromDate = moment() + .tz('America/Los_Angeles') + .startOf('week') + .subtract(offset, 'weeks') + .format('YYYY-MM-DDTHH:mm:ss'); + const toDate = moment() + .tz('America/Los_Angeles') + .endOf('week') + .subtract(offset, 'weeks') + .format('YYYY-MM-DDTHH:mm:ss'); const timeEntries = [ - { dateOfWork: moment().subtract(1, 'days').toISOString() }, - { dateOfWork: moment().subtract(2, 'days').toISOString() }, + { + dateOfWork: moment() + .subtract(1, 'days') + .toISOString(), + }, + { + dateOfWork: moment() + .subtract(2, 'days') + .toISOString(), + }, ]; // Sample time entries axios.get.mockResolvedValue({ data: timeEntries }); // Mock axios get response @@ -291,7 +355,9 @@ describe('timeEntries action creators', () => { offset, }); // Verify axios.get was called with the correct URL - expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, toDate)); + expect(axios.get).toHaveBeenCalledWith( + ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, toDate), + ); }); }); }); diff --git a/src/actions/__tests__/titleAction.test.js b/src/actions/__tests__/titleAction.test.js index 831cd44ba6..8997ba2bf1 100644 --- a/src/actions/__tests__/titleAction.test.js +++ b/src/actions/__tests__/titleAction.test.js @@ -45,7 +45,10 @@ describe('Title Actions', () => { describe('getAllTitle', () => { it('should return response when API call is successful', async () => { - const mockResponse = [{ id: '123', title: 'Title 1' }, { id: '124', title: 'Title 2' }]; + const mockResponse = [ + { id: '123', title: 'Title 1' }, + { id: '124', title: 'Title 2' }, + ]; jest.spyOn(titleActions, 'getAllTitle').mockResolvedValue(mockResponse); const response = await titleActions.getAllTitle(); diff --git a/src/actions/__tests__/userProfileActions.test.js b/src/actions/__tests__/userProfileActions.test.js index a96f9bf47f..7c61ab0099 100644 --- a/src/actions/__tests__/userProfileActions.test.js +++ b/src/actions/__tests__/userProfileActions.test.js @@ -17,6 +17,9 @@ jest.mock('axios'); jest.mock('react-toastify', () => ({ toast: { error: jest.fn(), + success: jest.fn(), + info: jest.fn(), + warn: jest.fn(), }, })); @@ -40,6 +43,7 @@ describe('User Profile Actions', () => { }); afterEach(() => { + // eslint-disable-next-line no-console console.log.mockRestore(); }); diff --git a/src/actions/__tests__/wbsActions.test.js b/src/actions/__tests__/wbsActions.test.js index 82177affff..a69d58520b 100644 --- a/src/actions/__tests__/wbsActions.test.js +++ b/src/actions/__tests__/wbsActions.test.js @@ -19,6 +19,7 @@ describe('WBS Action Creators', () => { }); afterEach(() => { jest.clearAllMocks(); + // eslint-disable-next-line no-console console.log.mockRestore(); }); diff --git a/src/actions/__tests__/weeklySummariesReportRecepients.js.test.js b/src/actions/__tests__/weeklySummariesReportRecepients.js.test.js index b92ccc488f..a0fe43487f 100644 --- a/src/actions/__tests__/weeklySummariesReportRecepients.js.test.js +++ b/src/actions/__tests__/weeklySummariesReportRecepients.js.test.js @@ -2,7 +2,16 @@ import axios from 'axios'; // Import axios for making HTTP requests import configureMockStore from 'redux-mock-store'; // Import redux-mock-store for creating a mock store import thunk from 'redux-thunk'; // Import redux-thunk for handling asynchronous actions import * as actions from '../../constants/weeklySummariesReport'; // Import the action type constants -import { authorizeWeeklySummaries, authorizeWeeklySummariesReportError, getRecepients, getRecepientsError, addSummaryRecipient, deleteRecipient, deleteSummaryRecipient, getSummaryRecipients } from '../weeklySummariesReportRecepients'; // Import the action creators +import { + authorizeWeeklySummaries, + authorizeWeeklySummariesReportError, + getRecepients, + getRecepientsError, + addSummaryRecipient, + deleteRecipient, + deleteSummaryRecipient, + getSummaryRecipients, +} from '../weeklySummariesReportRecepients'; // Import the action creators import { ENDPOINTS } from '../../utils/URL'; // Import the endpoints // Mock axios to control its behavior in tests @@ -27,7 +36,7 @@ describe('authorizeWeeklySummaries action creator', () => { // Define the expected action object const expectedAction = { type: actions.AUTHORIZE_WEEKLY_SUMMARY_REPORTS, - payload: message + payload: message, }; // Assert that the action creator returns the expected action object @@ -44,7 +53,7 @@ describe('authorizeWeeklySummariesReportError action creator', () => { // Define the expected action object const expectedAction = { type: actions.AUTHORIZE_WEEKLYSUMMARIES_REPORTS_ERROR, - payload: errorMsg + payload: errorMsg, }; // Assert that the action creator returns the expected action object @@ -61,7 +70,7 @@ describe('getRecepients action creator', () => { // Define the expected action object const expectedAction = { type: actions.GET_SUMMARY_RECIPIENTS, - recepientsArr + recepientsArr, }; // Assert that the action creator returns the expected action object @@ -78,7 +87,7 @@ describe('getRecepientsError action creator', () => { // Define the expected action object const expectedAction = { type: actions.GET_SUMMARY_RECIPIENTS_ERROR, - payload: err + payload: err, }; // Assert that the action creator returns the expected action object @@ -128,7 +137,7 @@ describe('addSummaryRecipient action creator', () => { const actionsDispatched = store.getActions(); expect(actionsDispatched).toContainEqual({ type: actions.AUTHORIZE_WEEKLYSUMMARIES_REPORTS_ERROR, - payload: new Error(errorMessage) + payload: new Error(errorMessage), }); }); }); @@ -142,7 +151,7 @@ describe('deleteRecipient action creator', () => { // Define the expected action object const expectedAction = { type: actions.DELETE_WEEKLY_SUMMARIES_RECIPIENTS, - payload: { userid } + payload: { userid }, }; // Assert that the action creator returns the expected action object @@ -175,7 +184,7 @@ describe('deleteSummaryRecipient action creator', () => { const actionsDispatched = store.getActions(); expect(actionsDispatched).toContainEqual({ type: actions.DELETE_WEEKLY_SUMMARIES_RECIPIENTS, - payload: { userid } + payload: { userid }, }); }); @@ -198,7 +207,7 @@ describe('deleteSummaryRecipient action creator', () => { const actionsDispatched = store.getActions(); expect(actionsDispatched).toContainEqual({ type: actions.AUTHORIZE_WEEKLYSUMMARIES_REPORTS_ERROR, - payload: new Error(errorMessage) + payload: new Error(errorMessage), }); }); }); @@ -226,7 +235,7 @@ describe('getSummaryRecipients action creator', () => { const actionsDispatched = store.getActions(); expect(actionsDispatched).toContainEqual({ type: actions.GET_SUMMARY_RECIPIENTS, - recepientsArr: responseData + recepientsArr: responseData, }); }); @@ -247,7 +256,7 @@ describe('getSummaryRecipients action creator', () => { const actionsDispatched = store.getActions(); expect(actionsDispatched).toContainEqual({ type: actions.GET_SUMMARY_RECIPIENTS_ERROR, - payload: new Error(errorMessage) + payload: new Error(errorMessage), }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/allTeamsAction.js b/src/actions/allTeamsAction.js index 41447d3651..6e1944c6f6 100644 --- a/src/actions/allTeamsAction.js +++ b/src/actions/allTeamsAction.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; import { @@ -16,7 +17,6 @@ import { FETCH_ALL_TEAM_CODE_SUCCESS, FETCH_ALL_TEAM_CODE_FAILURE, } from '../constants/allTeamsConstants'; - /** * set allteams in store * @param payload : allteams [] @@ -112,7 +112,6 @@ export const updateVisibilityAction = (visibility, userId, teamId) => ({ teamId, }); - /** * fetching all user teams */ @@ -149,11 +148,11 @@ export const postNewTeam = (name, status, source) => { .catch(error => { if (error.response) { return error.response; // return the server response - } else if (error.request) { + } + if (error.request) { return { status: 500, message: 'No response received from the server' }; - } else { - return { status: 500, message: error.message }; } + return { status: 500, message: error.message }; }); }; }; @@ -227,7 +226,7 @@ export const deleteTeamMember = (teamId, userId) => { /** * Adding an existing user to team */ -export const addTeamMember = (teamId, userId, firstName, lastName, role, addDateTime) => { +export const addTeamMember = (teamId, userId) => { const requestData = { userId, operation: 'Assign' }; const teamMemberAddPromise = axios.post(ENDPOINTS.TEAM_USERS(teamId), requestData); return async dispatch => { @@ -243,19 +242,19 @@ export const updateTeamMemeberVisibility = (teamId, userId, visibility) => { return async dispatch => { updateVisibilityPromise - .then(res => { + .then(() => { dispatch(updateVisibilityAction(visibility, userId, teamId)); }) .catch(error => { if (error.response) { // The request was made and the server responded with a status code - console.error('Error updating visibility:', error.response.data); + toast.error('Error updating visibility:', error.response.data); } else if (error.request) { // The request was made but no response was received - console.error('Error updating visibility: No response received'); + toast.error('Error updating visibility: No response received'); } else { // Something happened in setting up the request that triggered an error - console.error('Error updating visibility:', error.message); + toast.error('Error updating visibility:', error.message); } }); }; diff --git a/src/actions/allUsersTimeEntries.js b/src/actions/allUsersTimeEntries.js index 8914e2552c..02f29e3619 100644 --- a/src/actions/allUsersTimeEntries.js +++ b/src/actions/allUsersTimeEntries.js @@ -5,7 +5,7 @@ import { ENDPOINTS } from '../utils/URL'; /** * Action to set the 'loading' flag to true. */ -export const fetchAllUsersTimeEntriesBegin= () => ({ +export const fetchAllUsersTimeEntriesBegin = () => ({ type: actions.FETCH_ALL_USERS_TIME_ENTRIES_BEGIN, }); @@ -33,9 +33,9 @@ export const getAllUsersTimeEntries = (users, fromDate, toDate) => { return async dispatch => { dispatch(fetchAllUsersTimeEntriesBegin()); try { - const { data: usersTimeEntries } = await axios.post(url, {users, fromDate, toDate}); + const { data: usersTimeEntries } = await axios.post(url, { users, fromDate, toDate }); dispatch(fetchAllUsersTimeEntriesSuccess(usersTimeEntries)); - return {status: usersTimeEntries.status, data: usersTimeEntries.data}; + return { status: usersTimeEntries.status, data: usersTimeEntries.data }; } catch (error) { dispatch(fetchAllUsersTimeEntriesError(error)); return error.usersTimeEntries.status; diff --git a/src/actions/authActions.js b/src/actions/authActions.js index 3279e4fc28..a5a9d97d87 100644 --- a/src/actions/authActions.js +++ b/src/actions/authActions.js @@ -8,6 +8,16 @@ import { SET_CURRENT_USER, SET_HEADER_DATA } from '../constants/auth'; const { tokenKey } = config; +export const setCurrentUser = decoded => ({ + type: SET_CURRENT_USER, + payload: decoded, +}); + +export const setHeaderData = data => ({ + type: SET_HEADER_DATA, + payload: data, +}); + export const loginUser = credentials => dispatch => { return httpService .post(ENDPOINTS.LOGIN, credentials) @@ -39,20 +49,20 @@ export const loginUser = credentials => dispatch => { }); }; -export const loginBMUser = (credentials) => async dispatch => { +export const loginBMUser = credentials => async dispatch => { return httpService .post(ENDPOINTS.BM_LOGIN, credentials) - .then((res) => { + .then(res => { localStorage.setItem(tokenKey, res.data.token); httpService.setjwt(res.data.token); - const decoded = jwtDecode(res.data.token) + const decoded = jwtDecode(res.data.token); dispatch(setCurrentUser(decoded)); - return res + return res; }) - .catch(err => err.response) -} + .catch(err => err.response); +}; -// end points needed for community Portal +// end points needed for community Portal // export const loginBMUser = (credentials) => async dispatch => { // return httpService @@ -99,13 +109,3 @@ export const refreshToken = userId => { return res.status; }; }; - -export const setCurrentUser = decoded => ({ - type: SET_CURRENT_USER, - payload: decoded, -}); - -export const setHeaderData = data => ({ - type: SET_HEADER_DATA, - payload: data, -}); \ No newline at end of file diff --git a/src/actions/badgeManagement.js b/src/actions/badgeManagement.js index 133e8a420c..348c47bb02 100644 --- a/src/actions/badgeManagement.js +++ b/src/actions/badgeManagement.js @@ -1,6 +1,6 @@ import axios from 'axios'; -import moment from 'moment'; -import { formatDate } from 'utils/formatDate'; +import { toast } from 'react-toastify'; +import { formatDate } from '../utils/formatDate'; import { GET_ALL_BADGE_DATA, ADD_SELECT_BADGE, @@ -24,7 +24,6 @@ const getAllBadges = allBadges => ({ }); export const fetchAllBadges = () => { - const url = ENDPOINTS.BADGE(); return async dispatch => { try { const response = await axios.get(ENDPOINTS.BADGE()); @@ -36,6 +35,39 @@ export const fetchAllBadges = () => { }; }; +// Return updated badgeCollection +export const returnUpdatedBadgesCollection = (badgeCollection, selectedBadgesId) => { + const personalMaxBadge = '666b78265bca0bcb94080605'; // backend id for Personal Max badge + const badgeMap = new Map(badgeCollection?.map(badge => [badge.badge, badge])); + + const currentTs = Date.now(); + const currentDate = formatDate(); + selectedBadgesId.forEach(originalBadgeId => { + const badgeId = originalBadgeId.replace('assign-badge-', ''); + if (badgeMap.has(badgeId)) { + // Update the existing badge record + if (badgeId !== personalMaxBadge) { + const badge = badgeMap.get(badgeId); + badge.count = (badge.count || 0) + 1; + badge.lastModified = currentTs; + badge.earnedDate.push(currentDate); + } + } else { + // Add the new badge record + badgeMap.set(badgeId, { + badge: badgeId, + count: 1, + lastModified: currentTs, + earnedDate: [currentDate], + }); + } + }); + + return Array.from(badgeMap.values()); +}; + +export const gotCloseAlert = () => ({ type: CLOSE_ALERT }); + const getBadgeCountSuccess = badgeCount => ({ type: GET_BADGE_COUNT, payload: badgeCount, @@ -46,8 +78,9 @@ export const getBadgeCount = userId => { try { const response = await axios.get(ENDPOINTS.BADGE_COUNT(userId)); dispatch(getBadgeCountSuccess(response.data.count)); + return response.data.count; } catch (err) { - return err.response.status; + return err.response?.status || 500; } }; }; @@ -63,7 +96,7 @@ export const resetBadgeCount = userId => async dispatch => { }); } } catch (error) { - console.error('Failed to reset badge count', error); + toast.error('Failed to reset badge count', error); } }; @@ -116,8 +149,6 @@ export const setActiveTab = tab => ({ payload: tab, }); -export const gotCloseAlert = () => ({ type: CLOSE_ALERT }); - export const validateBadges = (firstName, lastName) => { return async dispatch => { if (!firstName || !lastName) { @@ -225,14 +256,9 @@ export const assignBadgesByUserID = (userId, selectedBadges) => { } const userData = Array.isArray(res.data) ? res.data[0] : res.data; - + if (!userData || !userData._id || !userData.badgeCollection) { - dispatch( - getMessage( - "User data is incomplete. Cannot assign badges.", - 'danger', - ), - ); + dispatch(getMessage('User data is incomplete. Cannot assign badges.', 'danger')); setTimeout(() => { dispatch(closeAlert()); }, 6000); @@ -240,7 +266,7 @@ export const assignBadgesByUserID = (userId, selectedBadges) => { } const { badgeCollection } = userData; - for (let i = 0; i < badgeCollection.length; i++) { + for (let i = 0; i < badgeCollection.length; i += 1) { if (typeof badgeCollection[i].badge === 'object' && badgeCollection[i].badge) { badgeCollection[i].badge = badgeCollection[i].badge._id; } @@ -252,7 +278,7 @@ export const assignBadgesByUserID = (userId, selectedBadges) => { badgeCollection: newBadgeCollection, newBadges: selectedBadges.length, }); - + dispatch( getMessage( "Awesomesauce! Not only have you increased a person's badges, you've also proportionally increased their life happiness!", @@ -263,7 +289,7 @@ export const assignBadgesByUserID = (userId, selectedBadges) => { dispatch(closeAlert()); }, 6000); } catch (e) { - console.error("Badge assignment error:", e); + toast.error('Badge assignment error:', e); dispatch(getMessage('Oops, something is wrong!', 'danger')); setTimeout(() => { dispatch(closeAlert()); @@ -271,36 +297,6 @@ export const assignBadgesByUserID = (userId, selectedBadges) => { } }; }; -// Return updated badgeCollection -export const returnUpdatedBadgesCollection = (badgeCollection, selectedBadgesId) => { - const personalMaxBadge = '666b78265bca0bcb94080605'; // backend id for Personal Max badge - const badgeMap = new Map(badgeCollection?.map(badge => [badge.badge, badge])); - - const currentTs = Date.now(); - const currentDate = formatDate(); - selectedBadgesId.forEach(originalBadgeId => { - const badgeId = originalBadgeId.replace('assign-badge-', ''); - if (badgeMap.has(badgeId)) { - // Update the existing badge record - if (badgeId != personalMaxBadge) { - const badge = badgeMap.get(badgeId); - badge.count = (badge.count || 0) + 1; - badge.lastModified = currentTs; - badge.earnedDate.push(currentDate); - } - } else { - // Add the new badge record - badgeMap.set(badgeId, { - badge: badgeId, - count: 1, - lastModified: currentTs, - earnedDate: [currentDate], - }); - } - }); - - return Array.from(badgeMap.values()); -}; // Make API call to update badgeCollection export const sendUpdatedBadgeCollectionReq = async ( @@ -308,24 +304,26 @@ export const sendUpdatedBadgeCollectionReq = async ( selectedBadges, userToBeAssignedBadge, ) => { - const url = ENDPOINTS.BADGE_ASSIGN(userToBeAssignedBadge); - try { - await axios.put(url, { badgeCollection, newBadges: selectedBadges.length }); - dispatch( - getMessage( - "Awesomesauce! Not only have you increased a person's badges, you've also proportionally increased their life happiness!", - 'success', - ), - ); - setTimeout(() => { - dispatch(closeAlert()); - }, 6000); - } catch (e) { - dispatch(getMessage('Oops, something is wrong!', 'danger')); - setTimeout(() => { - dispatch(closeAlert()); - }, 6000); - } + return async dispatch => { + const url = ENDPOINTS.BADGE_ASSIGN(userToBeAssignedBadge); + try { + await axios.put(url, { badgeCollection, newBadges: selectedBadges.length }); + dispatch( + getMessage( + "Awesomesauce! Not only have you increased a person's badges, you've also proportionally increased their life happiness!", + 'success', + ), + ); + setTimeout(() => { + dispatch(closeAlert()); + }, 6000); + } catch (e) { + dispatch(getMessage('Oops, something is wrong!', 'danger')); + setTimeout(() => { + dispatch(closeAlert()); + }, 6000); + } + }; }; export const changeBadgesByUserID = (userId, badgeCollection) => { @@ -365,7 +363,7 @@ export const createNewBadge = newBadge => async dispatch => { }, 6000); dispatch(fetchAllBadges()); } catch (e) { - if (e.response.status === 403 || 400) { + if (e.response.status === 403 || e.response.status === 400) { dispatch(getMessage(e.response.data.error, 'danger')); setTimeout(() => { dispatch(closeAlert()); @@ -384,7 +382,7 @@ export const updateBadge = (badgeId, badgeData) => async dispatch => { await axios.put(ENDPOINTS.BADGE_BY_ID(badgeId), badgeData); dispatch(fetchAllBadges()); } catch (e) { - if (e.response.status === 403 || 400) { + if (e.response.status === 403 || e.response.status === 400) { dispatch(getMessage(e.response.data.error, 'danger')); setTimeout(() => { dispatch(closeAlert()); @@ -407,7 +405,7 @@ export const deleteBadge = badgeId => async dispatch => { }, 6000); dispatch(fetchAllBadges()); } catch (e) { - if (e.response.status === 403 || 400) { + if (e.response.status === 403 || e.response.status === 400) { dispatch(getMessage(e.response.data.error, 'danger')); setTimeout(() => { dispatch(closeAlert()); diff --git a/src/actions/blueSquareEmailBCCAction.js b/src/actions/blueSquareEmailBCCAction.js index d44c289fd8..15a339dd73 100644 --- a/src/actions/blueSquareEmailBCCAction.js +++ b/src/actions/blueSquareEmailBCCAction.js @@ -1,7 +1,7 @@ -import * as types from '../constants/BluequareEmailBccConstants'; import axios from 'axios'; -import { ENDPOINTS } from '../utils/URL'; import { toast } from 'react-toastify'; +import * as types from '../constants/BluequareEmailBccConstants'; +import { ENDPOINTS } from '../utils/URL'; const getAllBlueSquareEmailBccs = allAssignements => ({ type: types.GET_BLUE_SQUARE_EMAIL_ASSIGNMENTS, @@ -34,7 +34,7 @@ export const getAllBlueSquareEmailAssignements = () => { dispatch(blueSquareEmailBccError(response.data)); } } catch (err) { - dispatch(blueSquareEmailBccError(err)); + dispatch(blueSquareEmailBccError(err)); } }; }; @@ -43,31 +43,31 @@ export const setBlueSquareEmailAssignement = email => { const url = ENDPOINTS.BLUE_SQUARE_EMAIL_BCC(); return async dispatch => { try { - const response = await axios.post(url, {email}); + const response = await axios.post(url, { email }); if (response.status === 200) { dispatch(setBlueSquareEmailBcc(response.data)); } else { dispatch(blueSquareEmailBccError(response.data)); } } catch (err) { - dispatch(blueSquareEmailBccError(err)); + dispatch(blueSquareEmailBccError(err)); } }; }; export const deleteBlueSquareEmailAssignement = id => { - const url = ENDPOINTS.DELETE_BLUE_SQUARE_EMAIL_BCC(id); - return async dispatch => { - try { - const response = await axios.delete(url); - if (response.status === 200) { - console.log(response.data) - dispatch(deleteBlueSquareEmailBcc(response.data.id)); - } else { - dispatch(blueSquareEmailBccError(response.data)); - } - } catch (err) { - dispatch(blueSquareEmailBccError(err)); + const url = ENDPOINTS.DELETE_BLUE_SQUARE_EMAIL_BCC(id); + return async dispatch => { + try { + const response = await axios.delete(url); + if (response.status === 200) { + toast.info(response.data); + dispatch(deleteBlueSquareEmailBcc(response.data.id)); + } else { + dispatch(blueSquareEmailBccError(response.data)); } - }; + } catch (err) { + dispatch(blueSquareEmailBccError(err)); + } }; +}; diff --git a/src/actions/bmdashboard/equipmentActions.js b/src/actions/bmdashboard/equipmentActions.js index 2317c5286d..3d285610f4 100644 --- a/src/actions/bmdashboard/equipmentActions.js +++ b/src/actions/bmdashboard/equipmentActions.js @@ -1,70 +1,74 @@ -import axios from "axios"; -import { ENDPOINTS } from "utils/URL"; -import GET_EQUIPMENT_BY_ID, {SET_EQUIPMENTS} from 'constants/bmdashboard/equipmentConstants'; -import { GET_ERRORS } from 'constants/errors'; +import axios from 'axios'; +import { SET_EQUIPMENTS } from '../../constants/bmdashboard/equipmentConstants'; +import { GET_ERRORS } from '../../constants/errors'; +import { ENDPOINTS } from '../../utils/URL'; -export const fetchEquipmentById = (equipmentId) => { +export const setEquipment = payload => { + return { + type: SET_EQUIPMENTS, + payload, + }; +}; + +export const setEquipments = payload => { + return { + type: SET_EQUIPMENTS, + payload, + }; +}; + +export const setErrors = payload => { + return { + type: GET_ERRORS, + payload, + }; +}; + +export const fetchEquipmentById = equipmentId => { const url = ENDPOINTS.BM_EQUIPMENT_BY_ID(equipmentId); return async dispatch => { - axios.get(url) + axios + .get(url) .then(res => { - dispatch(setEquipment(res.data)) + dispatch(setEquipment(res.data)); }) .catch(error => { - dispatch(setErrors(error)) - }) - } -} + dispatch(setErrors(error)); + }); + }; +}; export const fetchAllEquipments = () => { return async dispatch => { - axios.get(ENDPOINTS.BM_EQUIPMENTS) + axios + .get(ENDPOINTS.BM_EQUIPMENTS) .then(res => { - dispatch(setEquipments(res.data)) + dispatch(setEquipments(res.data)); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; -export const setEquipments = payload => { - return { - type: SET_EQUIPMENTS, - payload - } -} - -export const addEquipmentType = async (body) => { - return axios.post(`${ENDPOINTS.BM_INVTYPE_ROOT}/equipment`, body) +export const addEquipmentType = async body => { + return axios + .post(`${ENDPOINTS.BM_INVTYPE_ROOT}/equipment`, body) .then(res => res) - .catch((err) => { - if (err.response) return err.response - if (err.request) return err.request - return err.message - }) -} - -export const setEquipment = payload => { - return { - type: SET_EQUIPMENTS, - payload - } -} - -export const setErrors = payload => { - return { - type: GET_ERRORS, - payload - } -} + .catch(err => { + if (err.response) return err.response; + if (err.request) return err.request; + return err.message; + }); +}; -export const purchaseEquipment = async (body) => { - return axios.post(ENDPOINTS.BM_EQUIPMENT_PURCHASE, body) +export const purchaseEquipment = async body => { + return axios + .post(ENDPOINTS.BM_EQUIPMENT_PURCHASE, body) .then(res => res) - .catch((err) => { - if (err.response) return err.response - if (err.request) return err.request - return err.message - }) -} \ No newline at end of file + .catch(err => { + if (err.response) return err.response; + if (err.request) return err.request; + return err.message; + }); +}; diff --git a/src/actions/bmdashboard/invTypeActions.js b/src/actions/bmdashboard/invTypeActions.js index 5e2a4bc6c8..a7fd939754 100644 --- a/src/actions/bmdashboard/invTypeActions.js +++ b/src/actions/bmdashboard/invTypeActions.js @@ -1,54 +1,175 @@ import axios from 'axios'; -import { ENDPOINTS } from "utils/URL"; -import GET_MATERIAL_TYPES, { POST_BUILDING_MATERIAL_INVENTORY_TYPE, - POST_ERROR_BUILDING_MATERIAL_INVENTORY_TYPE, - RESET_POST_BUILDING_MATERIAL_INVENTORY_TYPE, - POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, - POST_ERROR_BUILDING_CONSUMABLE_INVENTORY_TYPE, - RESET_POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, - POST_BUILDING_TOOL_INVENTORY_TYPE, - POST_ERROR_BUILDING_TOOL_INVENTORY_TYPE, - RESET_POST_BUILDING_TOOL_INVENTORY_TYPE, - GET_INV_BY_TYPE, GET_TOOL_TYPES , - GET_CONSUMABLE_TYPES, GET_REUSABLE_TYPES } from "constants/bmdashboard/inventoryTypeConstants"; -import { POST_TOOLS_LOG, POST_ERROR_TOOLS_LOG, RESET_POST_TOOLS_LOG } from 'constants/bmdashboard/toolsConstants'; -import { GET_ERRORS } from "constants/errors"; +import GET_MATERIAL_TYPES, { + POST_BUILDING_MATERIAL_INVENTORY_TYPE, + POST_ERROR_BUILDING_MATERIAL_INVENTORY_TYPE, + RESET_POST_BUILDING_MATERIAL_INVENTORY_TYPE, + POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, + POST_ERROR_BUILDING_CONSUMABLE_INVENTORY_TYPE, + RESET_POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, + POST_BUILDING_TOOL_INVENTORY_TYPE, + POST_ERROR_BUILDING_TOOL_INVENTORY_TYPE, + RESET_POST_BUILDING_TOOL_INVENTORY_TYPE, + GET_INV_BY_TYPE, + GET_TOOL_TYPES, + GET_CONSUMABLE_TYPES, + GET_REUSABLE_TYPES, + GET_EQUIPMENT_TYPES, +} from '../../constants/bmdashboard/inventoryTypeConstants'; +import { + POST_TOOLS_LOG, + POST_ERROR_TOOLS_LOG, + RESET_POST_TOOLS_LOG, +} from '../../constants/bmdashboard/toolsConstants'; +import { GET_ERRORS } from '../../constants/errors'; +import { ENDPOINTS } from '../../utils/URL'; + +export const setConsumableTypes = payload => { + return { + type: GET_CONSUMABLE_TYPES, + payload, + }; +}; + +export const setPostErrorBuildingConsumableTypeResult = payload => { + return { + type: POST_ERROR_BUILDING_CONSUMABLE_INVENTORY_TYPE, + payload, + }; +}; + +export const setPostErrorBuildingToolTypeResult = payload => { + return { + type: POST_ERROR_BUILDING_TOOL_INVENTORY_TYPE, + payload, + }; +}; + +export const resetPostBuildingInventoryTypeResult = () => { + return { + type: RESET_POST_BUILDING_MATERIAL_INVENTORY_TYPE, + }; +}; + +export const resetPostBuildingConsumableTypeResult = () => { + return { + type: RESET_POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, + }; +}; + +export const resetPostBuildingToolTypeResult = () => { + return { + type: RESET_POST_BUILDING_TOOL_INVENTORY_TYPE, + }; +}; + +export const setMaterialTypes = payload => { + return { + type: GET_MATERIAL_TYPES, + payload, + }; +}; + +export const setEquipmentTypes = payload => { + return { + type: GET_EQUIPMENT_TYPES, + payload, + }; +}; + +export const setReusableTypes = payload => { + return { + type: GET_REUSABLE_TYPES, + payload, + }; +}; + +export const setToolTypes = payload => { + return { + type: GET_TOOL_TYPES, + payload, + }; +}; + +export const setInvTypesByType = payload => { + return { + type: GET_INV_BY_TYPE, + payload, + }; +}; + +export const setErrors = payload => { + return { + type: GET_ERRORS, + payload, + }; +}; + +export const setPostBuildingInventoryTypeResult = payload => { + return { + type: POST_BUILDING_MATERIAL_INVENTORY_TYPE, + payload, + }; +}; + +export const setPostBuildingConsumableTypeResult = payload => { + return { + type: POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, + payload, + }; +}; + +export const setPostBuildingToolTypeResult = payload => { + return { + type: POST_BUILDING_TOOL_INVENTORY_TYPE, + payload, + }; +}; + +export const setPostErrorBuildingInventoryTypeResult = payload => { + return { + type: POST_ERROR_BUILDING_MATERIAL_INVENTORY_TYPE, + payload, + }; +}; export const fetchMaterialTypes = () => { return async dispatch => { - axios.get(ENDPOINTS.BM_MATERIAL_TYPES) + axios + .get(ENDPOINTS.BM_MATERIAL_TYPES) .then(res => { - dispatch(setMaterialTypes(res.data)) + dispatch(setMaterialTypes(res.data)); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; export const fetchEquipmentTypes = () => { return async dispatch => { - axios.get(ENDPOINTS.BM_EQUIPMENT_TYPES) + axios + .get(ENDPOINTS.BM_EQUIPMENT_TYPES) .then(res => { - dispatch(setEquipmentTypes(res.data)) + dispatch(setEquipmentTypes(res.data)); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; export const fetchReusableTypes = () => { return async dispatch => { - axios.get(ENDPOINTS.BM_REUSABLE_TYPES) - .then(res => { - dispatch(setReusableTypes(res.data)) + axios + .get(ENDPOINTS.BM_REUSABLE_TYPES) + .then(res => { + dispatch(setReusableTypes(res.data)); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; export const fetchToolTypes = () => { return async dispatch => { @@ -65,18 +186,19 @@ export const fetchToolTypes = () => { }; }; -export const fetchInvTypeByType = (type) => { +export const fetchInvTypeByType = type => { const url = ENDPOINTS.BM_INVTYPE_TYPE(type); return async dispatch => { - axios.get(url) + axios + .get(url) .then(res => { - dispatch(setInvTypesByType({ type: type, data: res.data })) + dispatch(setInvTypesByType({ type, data: res.data })); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; export const postBuildingConsumableType = payload => { return async dispatch => { @@ -112,48 +234,23 @@ export const postBuildingToolType = payload => { }; }; -export const postBuildingInventoryType = (payload) => { +export const postBuildingInventoryType = payload => { return async dispatch => { - axios.post(ENDPOINTS.BM_MATERIAL_TYPE, payload) + axios + .post(ENDPOINTS.BM_MATERIAL_TYPE, payload) .then(res => { - dispatch(setPostBuildingInventoryTypeResult(res.data)) + dispatch(setPostBuildingInventoryTypeResult(res.data)); }) .catch(err => { - dispatch(setPostErrorBuildingInventoryTypeResult(JSON.stringify(err.response.data) || 'Sorry! Some error occurred!')) - }) - } -} - -export const setPostBuildingInventoryTypeResult = (payload) => { - return { - type: POST_BUILDING_MATERIAL_INVENTORY_TYPE, - payload - } -} - - -export const setPostBuildingConsumableTypeResult = payload => { - return { - type: POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, - payload, - }; -}; - -export const setPostBuildingToolTypeResult = payload => { - return { - type: POST_BUILDING_TOOL_INVENTORY_TYPE, - payload, + dispatch( + setPostErrorBuildingInventoryTypeResult( + JSON.stringify(err.response.data) || 'Sorry! Some error occurred!', + ), + ); + }); }; }; - -export const setPostErrorBuildingInventoryTypeResult = (payload) => { - return { - type: POST_ERROR_BUILDING_MATERIAL_INVENTORY_TYPE, - payload - } -} - export const fetchConsumableTypes = () => { return async dispatch => { axios @@ -165,90 +262,8 @@ export const fetchConsumableTypes = () => { dispatch(setErrors(err)); }); }; -} - -export const setConsumableTypes = payload => { - return { - type: GET_CONSUMABLE_TYPES, - payload, - }; -} - -export const setPostErrorBuildingConsumableTypeResult = payload => { - return { - type: POST_ERROR_BUILDING_CONSUMABLE_INVENTORY_TYPE, - payload, - }; -}; - -export const setPostErrorBuildingToolTypeResult = payload => { - return { - type: POST_ERROR_BUILDING_TOOL_INVENTORY_TYPE, - payload, - }; -}; - -export const resetPostBuildingInventoryTypeResult = () => { - return { - type: RESET_POST_BUILDING_MATERIAL_INVENTORY_TYPE - } -} - -export const resetPostBuildingConsumableTypeResult = () => { - return { - type: RESET_POST_BUILDING_CONSUMABLE_INVENTORY_TYPE, - }; -}; - -export const resetPostBuildingToolTypeResult = () => { - return { - type: RESET_POST_BUILDING_TOOL_INVENTORY_TYPE, - }; }; - -export const setMaterialTypes = payload => { - return { - type: GET_MATERIAL_TYPES, - payload - } -} - -export const setEquipmentTypes = payload => { - return { - type: GET_EQUIPMENT_TYPES, - payload - } -} - -export const setReusableTypes = payload => { - return { - type: GET_REUSABLE_TYPES, - payload - } -} - -export const setToolTypes = payload => { - return { - type: GET_TOOL_TYPES, - payload, - }; -}; -export const setInvTypesByType = payload => { - - return { - type: GET_INV_BY_TYPE, - payload - } -} - -export const setErrors = payload => { - return { - type: GET_ERRORS, - payload - } -}; -// export const postToolsLog = payload => { return async dispatch => { axios @@ -286,4 +301,4 @@ export const resetPostToolsLog = () => { return { type: RESET_POST_TOOLS_LOG, }; -}; \ No newline at end of file +}; diff --git a/src/actions/bmdashboard/invUnitActions.js b/src/actions/bmdashboard/invUnitActions.js index 9bf2be5b7d..77529f4f4e 100644 --- a/src/actions/bmdashboard/invUnitActions.js +++ b/src/actions/bmdashboard/invUnitActions.js @@ -1,58 +1,62 @@ -import axios from "axios"; +import axios from 'axios'; -import { ENDPOINTS } from "utils/URL"; +import { ENDPOINTS } from '../../utils/URL'; import { FETCH_BUILDING_MATERIAL_INVENTORY_UNITS, - POST_BUILDING_MATERIAL_INVENTORY_UNIT, RESET_POST_BUILDING_MATERIAL_INVENTORY_UNIT -} from "constants/bmdashboard/inventoryTypeConstants"; import { GET_ERRORS } from "constants/errors"; + POST_BUILDING_MATERIAL_INVENTORY_UNIT, + RESET_POST_BUILDING_MATERIAL_INVENTORY_UNIT, +} from '../../constants/bmdashboard/inventoryTypeConstants'; +import { GET_ERRORS } from '../../constants/errors'; -export const fetchInvUnits = () => { - return async dispatch => { - axios.get(ENDPOINTS.BM_INVENTORY_UNITS) - .then(res => { - dispatch(setInvUnits(res.data)) - }) - .catch(err => { - dispatch(setErrors(err)) - }) - } -} - -export const postBuildingInventoryUnit = (payload) => { - return async dispatch => { - axios.post(ENDPOINTS.BM_INVENTORY_UNITS, payload) - .then(res => { - dispatch(setPostInvUnitResult(res.data)) - }) - .catch(err => { - dispatch(setErrors(err)) - }) - } -} - -export const setPostInvUnitResult = (payload) => { +export const setPostInvUnitResult = payload => { return { type: POST_BUILDING_MATERIAL_INVENTORY_UNIT, - payload - } -} + payload, + }; +}; export const resetPostInvUnitResult = () => { return { - type: RESET_POST_BUILDING_MATERIAL_INVENTORY_UNIT - } -} + type: RESET_POST_BUILDING_MATERIAL_INVENTORY_UNIT, + }; +}; export const setInvUnits = payload => { return { type: FETCH_BUILDING_MATERIAL_INVENTORY_UNITS, - payload - } -} + payload, + }; +}; export const setErrors = payload => { return { type: GET_ERRORS, - payload - } -} \ No newline at end of file + payload, + }; +}; + +export const fetchInvUnits = () => { + return async dispatch => { + axios + .get(ENDPOINTS.BM_INVENTORY_UNITS) + .then(res => { + dispatch(setInvUnits(res.data)); + }) + .catch(err => { + dispatch(setErrors(err)); + }); + }; +}; + +export const postBuildingInventoryUnit = payload => { + return async dispatch => { + axios + .post(ENDPOINTS.BM_INVENTORY_UNITS, payload) + .then(res => { + dispatch(setPostInvUnitResult(res.data)); + }) + .catch(err => { + dispatch(setErrors(err)); + }); + }; +}; diff --git a/src/actions/bmdashboard/lessonLikesActions.js b/src/actions/bmdashboard/lessonLikesActions.js index 9761e13253..7ec5588835 100644 --- a/src/actions/bmdashboard/lessonLikesActions.js +++ b/src/actions/bmdashboard/lessonLikesActions.js @@ -1,7 +1,8 @@ -import axios from "axios"; -import { ENDPOINTS } from "utils/URL"; -import { fetchBMLessons} from "./lessonsAction"; -import {BM_LESSON_LIKES} from '../../constants/bmdashboard/lessonConstants' +import axios from 'axios'; +import { toast } from 'react-toastify'; +import { ENDPOINTS } from '../../utils/URL'; +import { fetchBMLessons } from './lessonsAction'; +import { BM_LESSON_LIKES } from '../../constants/bmdashboard/lessonConstants'; export const likeLessonAction = (lessonIndex, userId) => { const url = ENDPOINTS.BM_LESSON_LIKES(lessonIndex); @@ -11,23 +12,21 @@ export const likeLessonAction = (lessonIndex, userId) => { lessonIndex, userId, }); - - if (response.status === 200) { - dispatch(fetchBMLessons()) + if (response.status === 200) { + dispatch(fetchBMLessons()); } else { - console.error('Unexpected response status:', response.status); + toast.error('Unexpected response status:', response.status); } } catch (error) { - console.error('Error liking lesson:', error); + toast.error('Error liking lesson:', error); } }; }; - export const setLikes = payload => { return { type: BM_LESSON_LIKES, - payload - } -} \ No newline at end of file + payload, + }; +}; diff --git a/src/actions/bmdashboard/lessonsAction.js b/src/actions/bmdashboard/lessonsAction.js index 38027d5e33..2b63f5217a 100644 --- a/src/actions/bmdashboard/lessonsAction.js +++ b/src/actions/bmdashboard/lessonsAction.js @@ -1,9 +1,49 @@ -import axios from "axios"; -import { ENDPOINTS } from "utils/URL"; -import { GET_BM_LESSONS, UPDATE_LESSON, DELETE_LESSON, SET_LESSON } from "constants/bmdashboard/lessonConstants"; -import { getUserProfile } from "actions/userProfile"; -import { fetchProjectById } from "actions/bmdashboard/projectByIdAction"; +import axios from 'axios'; +import { toast } from 'react-toastify'; +import { ENDPOINTS } from '../../utils/URL'; +import { + GET_BM_LESSONS, + UPDATE_LESSON, + DELETE_LESSON, + SET_LESSON, +} from '../../constants/bmdashboard/lessonConstants'; +import { getUserProfile } from '../userProfile'; +import { fetchProjectById } from './projectByIdAction'; +import { GET_ERRORS } from '../../constants/errors'; +export const deleteLesson = lessonId => { + return { + type: DELETE_LESSON, + lessonId, + }; +}; + +export const setErrors = payload => { + return { + type: GET_ERRORS, + payload, + }; +}; + +export const updateLesson = (lessonId, content) => { + return { + type: UPDATE_LESSON, + lessonId, + content, + }; +}; + +export const setLesson = updatedLesson => ({ + type: SET_LESSON, + payload: updatedLesson, +}); + +export const setLessons = payload => { + return { + type: GET_BM_LESSONS, + payload, + }; +}; export const fetchBMLessons = () => { return async dispatch => { @@ -16,44 +56,38 @@ export const fetchBMLessons = () => { // Fetch user profiles and project details concurrently const [projectDetails, userProfiles] = await Promise.all([ Promise.all(projectIds.map(projectId => dispatch(fetchProjectById(projectId)))), - Promise.all(authorIds.map(authorId => dispatch(getUserProfile(authorId)))) + Promise.all(authorIds.map(authorId => dispatch(getUserProfile(authorId)))), ]); const updatedLessons = lessons.map((lesson, index) => { return { - ...lesson, - author: userProfiles[index] - ? { - id: userProfiles[index]._id, - name: `${userProfiles[index].firstName} ${userProfiles[index].lastName}`, - } - : lesson.author, - relatedProject: projectDetails[index] - ? { - id: projectDetails[index]._id, - name: projectDetails[index].projectName, - } - : lesson.relatedProject, - }; + ...lesson, + author: userProfiles[index] + ? { + id: userProfiles[index]._id, + name: `${userProfiles[index].firstName} ${userProfiles[index].lastName}`, + } + : lesson.author, + relatedProject: projectDetails[index] + ? { + id: projectDetails[index]._id, + name: projectDetails[index].projectName, + } + : lesson.relatedProject, + }; }); // Dispatch an action to update the lessons with the new author and project info dispatch(setLessons(updatedLessons)); } catch (error) { - console.error('Error fetching lessons:', error); + toast.error('Error fetching lessons:', error); dispatch(setErrors(error)); } }; }; -export const setLessons = payload => { - return { - type: GET_BM_LESSONS, - payload - } -} -export const fetchSingleBMLesson = (lessonId) => { +export const fetchSingleBMLesson = lessonId => { const url = ENDPOINTS.BM_LESSON + lessonId; - return async (dispatch) => { + return async dispatch => { try { const response = await axios.get(url); const lesson = response.data; @@ -82,57 +116,33 @@ export const fetchSingleBMLesson = (lessonId) => { }; dispatch(setLesson(updatedLesson)); } catch (error) { - console.error('Error fetching lesson:', error); + toast.error('Error fetching lesson:', error); dispatch(setErrors(error)); } }; }; -export const setLesson = (updatedLesson) => ({ - type: SET_LESSON, - payload: updatedLesson, -}); - export const updateBMLesson = (lessonId, content) => { return async dispatch => { const url = ENDPOINTS.BM_LESSON + lessonId; try { await axios.put(url, { content }); } catch (err) { - console.log('err') + toast.info('err'); } dispatch(updateLesson()); }; -} +}; -export const updateLesson = (lessonId, content) => { - return { - type: UPDATE_LESSON, - lessonId, - content, +export const deleteBMLesson = lessonId => { + return async dispatch => { + const url = ENDPOINTS.BM_LESSON + lessonId; + try { + await axios.delete(url); + } catch (err) { + toast.info('err'); + } + dispatch(deleteLesson(lessonId)); + dispatch(fetchBMLessons()); }; }; - - - - export const deleteBMLesson = (lessonId) => { - return async dispatch => { - const url = ENDPOINTS.BM_LESSON + lessonId; - try { - await axios.delete(url); - } catch (err) { - console.log('err') - } - dispatch(deleteLesson(lessonId)); - dispatch(fetchBMLessons()) - - }; - - } - - export const deleteLesson = (lessonId) => { - return { - type: DELETE_LESSON, - lessonId - }; - }; \ No newline at end of file diff --git a/src/actions/bmdashboard/materialsActions.js b/src/actions/bmdashboard/materialsActions.js index dba2fb57a7..2545e415e7 100644 --- a/src/actions/bmdashboard/materialsActions.js +++ b/src/actions/bmdashboard/materialsActions.js @@ -1,75 +1,84 @@ -import axios from "axios"; +import axios from 'axios'; -import { ENDPOINTS } from "utils/URL"; -import { - SET_MATERIALS, POST_UPDATE_MATERIAL_START, POST_UPDATE_MATERIAL_END, RESET_UPDATE_MATERIAL, - POST_UPDATE_MATERIAL_ERROR, POST_UPDATE_MATERIAL_START_BULK, POST_UPDATE_MATERIAL_END_BULK, - RESET_UPDATE_MATERIAL_BULK, POST_UPDATE_MATERIAL_ERROR_BULK, UPDATE_MATERIAL_STATUS_END, UPDATE_MATERIAL_STATUS_ERROR, UPDATE_MATERIAL_STATUS_START, -} from "constants/bmdashboard/materialsConstants"; -import { GET_ERRORS } from "constants/errors"; import { toast } from 'react-toastify'; +import { GET_ERRORS } from '../../constants/errors'; +import { ENDPOINTS } from '../../utils/URL'; +import { + SET_MATERIALS, + POST_UPDATE_MATERIAL_START, + POST_UPDATE_MATERIAL_END, + RESET_UPDATE_MATERIAL, + POST_UPDATE_MATERIAL_ERROR, + POST_UPDATE_MATERIAL_START_BULK, + POST_UPDATE_MATERIAL_END_BULK, + RESET_UPDATE_MATERIAL_BULK, + POST_UPDATE_MATERIAL_ERROR_BULK, + UPDATE_MATERIAL_STATUS_END, + UPDATE_MATERIAL_STATUS_ERROR, + UPDATE_MATERIAL_STATUS_START, +} from '../../constants/bmdashboard/materialsConstants'; export const setMaterials = payload => { return { type: SET_MATERIALS, - payload - } -} + payload, + }; +}; export const setErrors = payload => { return { type: GET_ERRORS, - payload - } -} + payload, + }; +}; export const materialUpdateStart = () => { return { - type: POST_UPDATE_MATERIAL_START - } -} + type: POST_UPDATE_MATERIAL_START, + }; +}; export const materialUpdateEnd = payload => { return { type: POST_UPDATE_MATERIAL_END, - payload - } -} + payload, + }; +}; export const materialUpdateError = payload => { return { type: POST_UPDATE_MATERIAL_ERROR, - payload - } -} + payload, + }; +}; export const resetMaterialUpdate = () => { - return { type: RESET_UPDATE_MATERIAL } -} + return { type: RESET_UPDATE_MATERIAL }; +}; export const materialUpdateStartBulk = () => { return { - type: POST_UPDATE_MATERIAL_START_BULK - } -} + type: POST_UPDATE_MATERIAL_START_BULK, + }; +}; export const materialUpdateEndBulk = payload => { return { type: POST_UPDATE_MATERIAL_END_BULK, - payload - } -} + payload, + }; +}; export const materialUpdateErrorBulk = payload => { return { type: POST_UPDATE_MATERIAL_ERROR_BULK, - payload - } -} + payload, + }; +}; export const resetMaterialUpdateBulk = () => { - return { type: RESET_UPDATE_MATERIAL_BULK } -} + return { type: RESET_UPDATE_MATERIAL_BULK }; +}; export const statusUpdateStart = () => { return { type: UPDATE_MATERIAL_STATUS_START }; @@ -89,34 +98,35 @@ export const statusUpdateError = payload => { }; }; - export const fetchAllMaterials = () => { return async dispatch => { - axios.get(ENDPOINTS.BM_MATERIALS) - // .then(res => { + axios + .get(ENDPOINTS.BM_MATERIALS) + // .then(res => { // dispatch(setMaterials(res.data)) // }) .then(res => { const updatedMaterials = res.data.map(material => ({ ...material, - stockAvailable: material.stockBought - material.stockUsed - material.stockWasted + stockAvailable: material.stockBought - material.stockUsed - material.stockWasted, })); dispatch(setMaterials(updatedMaterials)); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; -export const postMaterialUpdate = (payload) => { +export const postMaterialUpdate = payload => { return async dispatch => { - dispatch(materialUpdateStart()) - axios.post(ENDPOINTS.BM_UPDATE_MATERIAL, payload) + dispatch(materialUpdateStart()); + axios + .post(ENDPOINTS.BM_UPDATE_MATERIAL, payload) .then(res => { - dispatch(materialUpdateEnd(res.data)) + dispatch(materialUpdateEnd(res.data)); }) - .catch((error) => { + .catch(error => { if (error.response) { dispatch(materialUpdateError(error.response.data)); } else if (error.request) { @@ -124,18 +134,19 @@ export const postMaterialUpdate = (payload) => { } else { dispatch(materialUpdateError(error)); } - }) - } -} + }); + }; +}; -export const postMaterialUpdateBulk = (payload) => { +export const postMaterialUpdateBulk = payload => { return async dispatch => { - dispatch(materialUpdateStartBulk()) - axios.post(ENDPOINTS.BM_UPDATE_MATERIAL_BULK, payload) + dispatch(materialUpdateStartBulk()); + axios + .post(ENDPOINTS.BM_UPDATE_MATERIAL_BULK, payload) .then(res => { - dispatch(materialUpdateEndBulk(res.data.result)) + dispatch(materialUpdateEndBulk(res.data.result)); }) - .catch((error) => { + .catch(error => { if (error.response) { dispatch(materialUpdateErrorBulk(error.response.data)); } else if (error.request) { @@ -143,19 +154,20 @@ export const postMaterialUpdateBulk = (payload) => { } else { dispatch(materialUpdateErrorBulk(error)); } - }) - } -} + }); + }; +}; -export const purchaseMaterial = async (body) => { - return axios.post(ENDPOINTS.BM_MATERIALS, body) +export const purchaseMaterial = async body => { + return axios + .post(ENDPOINTS.BM_MATERIALS, body) .then(res => res) - .catch((err) => { - if (err.response) return err.response - if (err.request) return err.request - return err.message - }) -} + .catch(err => { + if (err.response) return err.response; + if (err.request) return err.request; + return err.message; + }); +}; export const approvePurchase = (purchaseId, quantity) => { return async dispatch => { diff --git a/src/actions/bmdashboard/projectActions.js b/src/actions/bmdashboard/projectActions.js index d286e8ea27..9e41861f7c 100644 --- a/src/actions/bmdashboard/projectActions.js +++ b/src/actions/bmdashboard/projectActions.js @@ -1,31 +1,32 @@ -import axios from "axios"; +import axios from 'axios'; -import { ENDPOINTS } from "utils/URL"; -import GET_BM_PROJECTS from "constants/bmdashboard/projectConstants"; -import { GET_ERRORS } from "constants/errors"; - -export const fetchBMProjects = () => { - return async dispatch => { - axios.get(ENDPOINTS.BM_PROJECTS) - .then(res => { - dispatch(setProjects(res.data)) - }) - .catch(err => { - dispatch(setErrors(err)) - }) - } -} +import { ENDPOINTS } from '../../utils/URL'; +import GET_BM_PROJECTS from '../../constants/bmdashboard/projectConstants'; +import { GET_ERRORS } from '../../constants/errors'; export const setProjects = payload => { return { type: GET_BM_PROJECTS, - payload - } -} + payload, + }; +}; export const setErrors = payload => { - return { + return { type: GET_ERRORS, - payload - } -} \ No newline at end of file + payload, + }; +}; + +export const fetchBMProjects = () => { + return async dispatch => { + axios + .get(ENDPOINTS.BM_PROJECTS) + .then(res => { + dispatch(setProjects(res.data)); + }) + .catch(err => { + dispatch(setErrors(err)); + }); + }; +}; diff --git a/src/actions/bmdashboard/projectByIdAction.js b/src/actions/bmdashboard/projectByIdAction.js index 247e0b28c0..a554fb03bf 100644 --- a/src/actions/bmdashboard/projectByIdAction.js +++ b/src/actions/bmdashboard/projectByIdAction.js @@ -1,12 +1,25 @@ -import axios from "axios"; -import { ENDPOINTS } from "utils/URL"; -import GET_BM_PROJECT_BY_ID from "constants/bmdashboard/projectConstants"; -import { GET_ERRORS } from "constants/errors"; +import axios from 'axios'; +import { ENDPOINTS } from '../../utils/URL'; +import GET_BM_PROJECT_BY_ID from '../../constants/bmdashboard/projectConstants'; +import { GET_ERRORS } from '../../constants/errors'; +export const setProject = payload => { + return { + type: GET_BM_PROJECT_BY_ID, + payload, + }; +}; + +export const setErrors = payload => { + return { + type: GET_ERRORS, + payload, + }; +}; -export const fetchProjectById = (projectId) => { +export const fetchProjectById = projectId => { const url = ENDPOINTS.BM_PROJECT_BY_ID(projectId); - return async (dispatch) => { + return async dispatch => { try { const response = await axios.get(url); const projectData = response.data; @@ -21,17 +34,3 @@ export const fetchProjectById = (projectId) => { } }; }; - -export const setProject = payload => { - return { - type: GET_BM_PROJECT_BY_ID, - payload - } -} - -export const setErrors = payload => { - return { - type: GET_ERRORS, - payload - } -} \ No newline at end of file diff --git a/src/actions/bmdashboard/reusableActions.js b/src/actions/bmdashboard/reusableActions.js index f40721148f..fb32243c71 100644 --- a/src/actions/bmdashboard/reusableActions.js +++ b/src/actions/bmdashboard/reusableActions.js @@ -1,57 +1,113 @@ -import axios from "axios"; +import axios from 'axios'; import { - SET_REUSABLES, POST_UPDATE_REUSABLE_START, POST_UPDATE_REUSABLE_END, RESET_UPDATE_REUSABLE, - POST_UPDATE_REUSABLE_ERROR, POST_UPDATE_REUSABLE_START_BULK, POST_UPDATE_REUSABLE_END_BULK, - RESET_UPDATE_REUSABLE_BULK, POST_UPDATE_REUSABLE_ERROR_BULK -} from "constants/bmdashboard/reusableConstants" -import { GET_ERRORS } from "constants/errors"; -import { ENDPOINTS } from "utils/URL"; + SET_REUSABLES, + POST_UPDATE_REUSABLE_START, + POST_UPDATE_REUSABLE_END, + RESET_UPDATE_REUSABLE, + POST_UPDATE_REUSABLE_ERROR, + POST_UPDATE_REUSABLE_START_BULK, + POST_UPDATE_REUSABLE_END_BULK, + RESET_UPDATE_REUSABLE_BULK, + POST_UPDATE_REUSABLE_ERROR_BULK, +} from '../../constants/bmdashboard/reusableConstants'; +import { GET_ERRORS } from '../../constants/errors'; +import { ENDPOINTS } from '../../utils/URL'; + +export const reusableUpdateStart = () => { + return { + type: POST_UPDATE_REUSABLE_START, + }; +}; + +export const reusableUpdateEnd = payload => { + return { + type: POST_UPDATE_REUSABLE_END, + payload, + }; +}; + +export const reusableUpdateError = payload => { + return { + type: POST_UPDATE_REUSABLE_ERROR, + payload, + }; +}; + +export const resetReusableUpdate = () => { + return { type: RESET_UPDATE_REUSABLE }; +}; + +export const reusableUpdateStartBulk = () => { + return { + type: POST_UPDATE_REUSABLE_START_BULK, + }; +}; + +export const reusableUpdateEndBulk = payload => { + return { + type: POST_UPDATE_REUSABLE_END_BULK, + payload, + }; +}; + +export const reusableUpdateErrorBulk = payload => { + return { + type: POST_UPDATE_REUSABLE_ERROR_BULK, + payload, + }; +}; + +export const resetReusableUpdateBulk = () => { + return { type: RESET_UPDATE_REUSABLE_BULK }; +}; export const setReusables = payload => { return { type: SET_REUSABLES, - payload - } -} + payload, + }; +}; export const setErrors = payload => { return { type: GET_ERRORS, - payload - } -} + payload, + }; +}; export const fetchAllReusables = () => { return async dispatch => { - axios.get(ENDPOINTS.BM_REUSABLES) + axios + .get(ENDPOINTS.BM_REUSABLES) .then(res => { - dispatch(setReusables(res.data)) + dispatch(setReusables(res.data)); }) .catch(err => { - dispatch(setErrors(err)) - }) - } -} + dispatch(setErrors(err)); + }); + }; +}; -export const purchaseReusable = async (body) => { - return axios.post(ENDPOINTS.BM_PURCHASE_REUSABLES, body) +export const purchaseReusable = async body => { + return axios + .post(ENDPOINTS.BM_PURCHASE_REUSABLES, body) .then(res => res) - .catch((err) => { - if (err.response) return err.response - if (err.request) return err.request - return err.message - }) -} - + .catch(err => { + if (err.response) return err.response; + if (err.request) return err.request; + return err.message; + }); +}; -export const postReusableUpdate = (payload) => { +export const postReusableUpdate = payload => { return async dispatch => { - dispatch(reusableUpdateStart()) - axios.post(ENDPOINTS.BM_UPDATE_REUSABLE, payload) + dispatch(reusableUpdateStart()); + axios + .post(ENDPOINTS.BM_UPDATE_REUSABLE, payload) .then(res => { - dispatch(reusableUpdateEnd(res.data)) + dispatch(reusableUpdateEnd(res.data)); }) - .catch((error) => { + .catch(error => { if (error.response) { dispatch(reusableUpdateError(error.response.data)); } else if (error.request) { @@ -59,18 +115,19 @@ export const postReusableUpdate = (payload) => { } else { dispatch(reusableUpdateError(error)); } - }) - } -} + }); + }; +}; -export const postReusableUpdateBulk = (payload) => { +export const postReusableUpdateBulk = payload => { return async dispatch => { - dispatch(reusableUpdateStartBulk()) - axios.post(ENDPOINTS.BM_UPDATE_REUSABLE_BULK, payload) + dispatch(reusableUpdateStartBulk()); + axios + .post(ENDPOINTS.BM_UPDATE_REUSABLE_BULK, payload) .then(res => { - dispatch(reusableUpdateEndBulk(res.data.result)) + dispatch(reusableUpdateEndBulk(res.data.result)); }) - .catch((error) => { + .catch(error => { if (error.response) { dispatch(reusableUpdateErrorBulk(error.response.data)); } else if (error.request) { @@ -78,54 +135,6 @@ export const postReusableUpdateBulk = (payload) => { } else { dispatch(reusableUpdateErrorBulk(error)); } - }) - } -} - -export const reusableUpdateStart = () => { - return { - type: POST_UPDATE_REUSABLE_START - } -} - -export const reusableUpdateEnd = payload => { - return { - type: POST_UPDATE_REUSABLE_END, - payload - } -} - -export const reusableUpdateError = payload => { - return { - type: POST_UPDATE_REUSABLE_ERROR, - payload - } -} - -export const resetReusableUpdate = () => { - return { type: RESET_UPDATE_REUSABLE } -} - -export const reusableUpdateStartBulk = () => { - return { - type: POST_UPDATE_REUSABLE_START_BULK - } -} - -export const reusableUpdateEndBulk = payload => { - return { - type: POST_UPDATE_REUSABLE_END_BULK, - payload - } -} - -export const reusableUpdateErrorBulk = payload => { - return { - type: POST_UPDATE_REUSABLE_ERROR_BULK, - payload - } -} - -export const resetReusableUpdateBulk = () => { - return { type: RESET_UPDATE_REUSABLE_BULK } -} \ No newline at end of file + }); + }; +}; diff --git a/src/actions/bmdashboard/toolActions.js b/src/actions/bmdashboard/toolActions.js index e95adf2ad8..6c6b5700ad 100644 --- a/src/actions/bmdashboard/toolActions.js +++ b/src/actions/bmdashboard/toolActions.js @@ -3,19 +3,37 @@ import GET_TOOL_BY_ID, { GET_TOOLS } from '../../constants/bmdashboard/toolsCons import { GET_ERRORS } from '../../constants/errors'; import { ENDPOINTS } from '../../utils/URL'; +export const setTools = payload => { + return { + type: GET_TOOLS, + payload, + }; +}; + +export const setTool = payload => { + return { + type: GET_TOOL_BY_ID, + payload, + }; +}; + +export const setErrors = payload => { + return { + type: GET_ERRORS, + payload, + }; +}; + export const fetchTools = () => { const url = ENDPOINTS.BM_TOOLS; return async dispatch => { axios .get(url) .then(res => { - // eslint-disable-next-line no-use-before-define dispatch(setTools(res.data)); }) .catch(error => { - // eslint-disable-next-line no-console - console.log('err: ', error.response.data.message); - // eslint-disable-next-line no-use-before-define + // console.log('err: ', error.response.data.message); dispatch(setErrors(error)); }); }; @@ -45,24 +63,3 @@ export const purchaseTools = async body => { return err.message; }); }; - -export const setTools = payload => { - return { - type: GET_TOOLS, - payload, - }; -}; - -export const setTool = payload => { - return { - type: GET_TOOL_BY_ID, - payload, - }; -}; - -export const setErrors = payload => { - return { - type: GET_ERRORS, - payload, - }; -}; diff --git a/src/actions/dashboardActions.js b/src/actions/dashboardActions.js index 2f429806a0..74b8de1547 100644 --- a/src/actions/dashboardActions.js +++ b/src/actions/dashboardActions.js @@ -1,9 +1,21 @@ +import { toast } from 'react-toastify'; + export const INCREMENT_DASHBOARD_TASK_COUNT = 'INCREMENT_DASHBOARD_TASK_COUNT'; +export const UPDATE_SUMMARY_BAR_DATA = 'UPDATE_SUMMARY_BAR_DATA' -export const incrementDashboardTaskCount = (taskId) => { - console.log(`Dispatching incrementDashboardTaskCount for task ID: ${taskId}`); +export const incrementDashboardTaskCount = taskId => { + toast.info(`Dispatching incrementDashboardTaskCount for task ID: ${taskId}`); return { type: INCREMENT_DASHBOARD_TASK_COUNT, payload: { taskId }, }; }; + +export const updateSummaryBarData = ({summaryBarData}) => { + // eslint-disable-next-line no-console + console.log(summaryBarData); + return { + type: UPDATE_SUMMARY_BAR_DATA, + payload: { summaryBarData }, + }; +}; diff --git a/src/actions/errorsActions.js b/src/actions/errorsActions.js index fc38c3db6a..de992f1a13 100644 --- a/src/actions/errorsActions.js +++ b/src/actions/errorsActions.js @@ -1,5 +1,6 @@ import { CLEAR_ERRORS } from '../constants/errors'; +// eslint-disable-next-line import/prefer-default-export export const clearErrors = () => { return { type: CLEAR_ERRORS, diff --git a/src/actions/followUpActions.js b/src/actions/followUpActions.js index 7bb253c070..d7173d5f4e 100644 --- a/src/actions/followUpActions.js +++ b/src/actions/followUpActions.js @@ -1,7 +1,7 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; import * as types from '../constants/followUpConstants'; -import { toast } from 'react-toastify'; const getAllFollowUps = allFollowUps => ({ type: types.FETCH_ALL_FOLLOWUPS, @@ -27,11 +27,11 @@ export const fetchAllFollowUps = () => { dispatch(getAllFollowUps(response.data)); } else { dispatch(followUpFetchError(response.data)); - toast.error('Error: loading follow-up data.') + toast.error('Error: loading follow-up data.'); } } catch (err) { dispatch(followUpFetchError(err)); - toast.error('Error: loading follow-up data.') + toast.error('Error: loading follow-up data.'); } }; }; @@ -45,12 +45,11 @@ export const setUserFollowUp = (userId, taskId, updateData) => { dispatch(setFollowUp(response.data)); } else { dispatch(followUpFetchError(response.data)); - toast.error('Error: Unable to set follow-up.') + toast.error('Error: Unable to set follow-up.'); } } catch (err) { dispatch(followUpFetchError(err)); - toast.error('Error: Unable to set follow-up.') + toast.error('Error: Unable to set follow-up.'); } }; }; - diff --git a/src/actions/formActions.js b/src/actions/formActions.js index b263d8401d..1c1fa79f46 100644 --- a/src/actions/formActions.js +++ b/src/actions/formActions.js @@ -1,55 +1,63 @@ -import {ADD_QUESTION, UPDATE_QUESTION, GET_FORM_STATE, ADD_OPTION, UPDATE_OPTION, DELETE_QUESTION, RESET_FORM_STATE, DELETE_OPTION} from 'constants/form'; +import { + ADD_QUESTION, + UPDATE_QUESTION, + GET_FORM_STATE, + ADD_OPTION, + UPDATE_OPTION, + DELETE_QUESTION, + RESET_FORM_STATE, + DELETE_OPTION, +} from '../constants/form'; export const getFormState = () => { - return { - type: GET_FORM_STATE, - }; -} + return { + type: GET_FORM_STATE, + }; +}; export const resetFormState = () => { - return { - type: RESET_FORM_STATE, - }; -} + return { + type: RESET_FORM_STATE, + }; +}; export const addQuestion = () => { - return { - type: ADD_QUESTION, - }; -} + return { + type: ADD_QUESTION, + }; +}; export const updateQuestion = (id, data) => { - return { - type: UPDATE_QUESTION, - payload: { id, data }, - }; -} - -export const deleteQuestion = (id) => { - return { - type: DELETE_QUESTION, - payload: { id }, - }; -} - - -export const addOption = (id) => { - return { - type: ADD_OPTION, - payload: { id }, - }; -} + return { + type: UPDATE_QUESTION, + payload: { id, data }, + }; +}; + +export const deleteQuestion = id => { + return { + type: DELETE_QUESTION, + payload: { id }, + }; +}; + +export const addOption = id => { + return { + type: ADD_OPTION, + payload: { id }, + }; +}; export const updateOption = (questionId, optionId, data) => { - return { - type: UPDATE_OPTION, - payload: { questionId, optionId, data }, - }; -} + return { + type: UPDATE_OPTION, + payload: { questionId, optionId, data }, + }; +}; export const deleteOption = (questionId, optionId) => { - return { - type: DELETE_OPTION, - payload: { questionId, optionId }, - }; -} \ No newline at end of file + return { + type: DELETE_OPTION, + payload: { questionId, optionId }, + }; +}; diff --git a/src/actions/hgnFormAction.js b/src/actions/hgnFormAction.js index dd40b0e88f..dafc7e5fbd 100644 --- a/src/actions/hgnFormAction.js +++ b/src/actions/hgnFormAction.js @@ -1,15 +1,14 @@ -import { FETCH_FORM_DATA, SET_FORM_DATA } from "../constants/hgnFormConstants" +import { FETCH_FORM_DATA, SET_FORM_DATA } from '../constants/hgnFormConstants'; +export const fetchformData = () => { + return async dispatch => { + dispatch({ + type: FETCH_FORM_DATA, + }); + }; +}; -export const fetchformData=()=>{ - return async dispatch=>{ - dispatch({ - type:FETCH_FORM_DATA - }) - } -} - -export const setformData=(data)=>({ - type:SET_FORM_DATA, - payload:data -}) \ No newline at end of file +export const setformData = data => ({ + type: SET_FORM_DATA, + payload: data, +}); diff --git a/src/actions/index.js b/src/actions/index.js index bafec54c97..275ef533e4 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,14 +1,13 @@ -import httpService from '../services/httpService'; import axios from 'axios'; +import httpService from '../services/httpService'; import { ApiEndpoint } from '../utils/URL'; import { ENDPOINTS } from '../utils/URL'; - const APIEndpoint = ApiEndpoint; export function clearUserProfile() { return { type: 'CLEAR_USER_PROFILE' }; -}; +} export function getUserTeamMembers(userId) { const request = httpService.get(`${APIEndpoint}/userprofile/teammembers/${userId}`); @@ -21,7 +20,7 @@ export function getUserTeamMembers(userId) { }); }); }; -}; +} export function getUserProjectMembers(projectId) { const request = httpService.get(`${APIEndpoint}/userprofile/project/${projectId}`); @@ -34,7 +33,7 @@ export function getUserProjectMembers(projectId) { }); }); }; -}; +} export function getDashboardData(userId) { const request = httpService.get(`${APIEndpoint}/dashboard/${userId}`); @@ -47,7 +46,7 @@ export function getDashboardData(userId) { }); }); }; -}; +} export function getWeeklyDashboardData(userId, fromDate, toDate) { const request = httpService.get( @@ -62,7 +61,7 @@ export function getWeeklyDashboardData(userId, fromDate, toDate) { }); }); }; -}; +} export function getMonthlyDashboardData(userId, fromDate, toDate) { const request = httpService.get( @@ -77,7 +76,7 @@ export function getMonthlyDashboardData(userId, fromDate, toDate) { }); }); }; -}; +} export function getLeaderboardData(userId) { const request = httpService.get(`${APIEndpoint}/dashboard/leaderboard/${userId}`); @@ -90,7 +89,7 @@ export function getLeaderboardData(userId) { }); }); }; -}; +} export function getActionItems(userId) { const request = httpService.get(`${APIEndpoint}/actionItem/user/${userId}`); @@ -103,7 +102,7 @@ export function getActionItems(userId) { }); }); }; -}; +} export function getNotifications(userId) { const request = httpService.get(`${APIEndpoint}/notification/user/${userId}`); @@ -116,7 +115,7 @@ export function getNotifications(userId) { }); }); }; -}; +} export function getAllProjects() { const request = httpService.get(`${APIEndpoint}/projects`); @@ -129,7 +128,7 @@ export function getAllProjects() { }); }); }; -}; +} export function getProjectById(projectId) { const request = httpService.get(`${APIEndpoint}/project/${projectId}`); @@ -142,7 +141,7 @@ export function getProjectById(projectId) { }); }); }; -}; +} export function getProjectsByUser(userId) { const request = httpService.get(`${APIEndpoint}/projects/user/${userId}`); @@ -155,7 +154,7 @@ export function getProjectsByUser(userId) { }); }); }; -}; +} export function getProjectMembership(projectId) { const request = httpService.get(`${APIEndpoint}/project/${projectId}/users`); @@ -168,7 +167,7 @@ export function getProjectMembership(projectId) { }); }); }; -}; +} export function getAllTeams() { const request = httpService.get(`${APIEndpoint}/team`); @@ -180,7 +179,7 @@ export function getAllTeams() { }); }); }; -}; +} export function getTeamById(teamId) { const request = httpService.get(`${APIEndpoint}/team/${teamId}`); @@ -193,7 +192,7 @@ export function getTeamById(teamId) { }); }); }; -}; +} export function getTeamMembership(teamId) { const request = httpService.get(`${APIEndpoint}/team/${teamId}/users`); @@ -206,7 +205,7 @@ export function getTeamMembership(teamId) { }); }); }; -}; +} export function getAllTimeEntries() { const request = httpService.get(`${APIEndpoint}/TimeEntry`); @@ -219,7 +218,7 @@ export function getAllTimeEntries() { }); }); }; -}; +} export function getTimeEntryForSpecifiedPeriod(userId, fromDate, toDate) { const request = httpService.get(`${APIEndpoint}/TimeEntry/user/${userId}/${fromDate}/${toDate}`); @@ -232,7 +231,7 @@ export function getTimeEntryForSpecifiedPeriod(userId, fromDate, toDate) { }); }); }; -}; +} export function postTimeEntry(timeEntryObj) { const request = httpService.post(`${APIEndpoint}/TimeEntry`, timeEntryObj); @@ -242,33 +241,37 @@ export function postTimeEntry(timeEntryObj) { error => dispatch({ type: 'REQUEST_FAILED', error }), ); }; -}; +} export function getTimeEntryByProjectSpecifiedPeriod(projectId, fromDate, toDate) { - const request = httpService.get(`${APIEndpoint}/TimeEntry/projects/${projectId}/${fromDate}/${toDate}`); + const request = httpService.get( + `${APIEndpoint}/TimeEntry/projects/${projectId}/${fromDate}/${toDate}`, + ); return dispatch => { return new Promise((resolve, reject) => { - request.then(({ data }) => { - dispatch({ - type: 'GET_TIME_ENTRY_By_Project_FOR_SPECIFIED_PERIOD', - payload: data, + request + .then(({ data }) => { + dispatch({ + type: 'GET_TIME_ENTRY_By_Project_FOR_SPECIFIED_PERIOD', + payload: data, + }); + resolve(data); + }) + .catch(error => { + reject(error); }); - resolve(data); - }).catch(error => { - reject(error); - }); }); }; -}; +} export function getTimeEntryForOverDate(users, fromDate, toDate) { - const url = ENDPOINTS.TIME_ENTRIES_USER_LIST; - return axios.post(url, { users, fromDate, toDate }) - .then(response => response.data) - .catch(error => { - throw error; - }); + return axios + .post(url, { users, fromDate, toDate }) + .then(response => response.data) + .catch(error => { + throw error; + }); } diff --git a/src/actions/information.js b/src/actions/information.js index 4f54543b18..a8127be56a 100644 --- a/src/actions/information.js +++ b/src/actions/information.js @@ -1,75 +1,75 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import * as actions from '../constants/information'; import { ENDPOINTS } from '../utils/URL'; +// Action creators +export const deleteInfoSuccess = infoId => ({ + type: actions.DELETE_INFO_SUCCESS, + payload: infoId, +}); + +export const fetchInfosSuccess = infoCollectionsData => ({ + type: actions.FETCH_INFOS_SUCCESS, + payload: { infoCollectionsData }, +}); + +export const updateInfoSuccess = updatedInfo => ({ + type: actions.UPDATE_INFO_SUCCESS, + payload: updatedInfo, +}); + // Get infoCollections export const getInfoCollections = () => { - const url = ENDPOINTS.INFO_COLLECTIONS; return async dispatch => { try { - const response = await axios.get(url); + const response = await axios.get(ENDPOINTS.INFO_COLLECTIONS); dispatch(fetchInfosSuccess(response.data)); return response.status; } catch (error) { - console.error(error); + toast.error(error.message || 'Failed to fetch info collections.'); + return null; } }; }; // Add new info collection export const addInfoCollection = newInfo => { - const url = ENDPOINTS.INFO_COLLECTIONS; - return async dispatch => { + return async () => { try { - const response = await axios.post(url, newInfo); + const response = await axios.post(ENDPOINTS.INFO_COLLECTIONS, newInfo); return response.status; } catch (error) { - console.error(error); + toast.error(error.message || 'Failed to add info collection.'); + return null; } }; }; // Update info collection export const updateInfoCollection = (infoId, updatedInfo) => { - const url = ENDPOINTS.INFO_COLLECTION(infoId); return async dispatch => { try { - const response = await axios.put(url, updatedInfo); + const response = await axios.put(ENDPOINTS.INFO_COLLECTION(infoId), updatedInfo); dispatch(updateInfoSuccess(response.data)); return response.status; } catch (error) { - console.error(error); + toast.error(error.message || 'Failed to update info collection.'); + return null; } }; }; // Delete info collection by id export const deleteInfoCollectionById = infoId => { - const url = ENDPOINTS.INFO_COLLECTION(infoId); return async dispatch => { try { - const response = await axios.delete(url); + const response = await axios.delete(ENDPOINTS.INFO_COLLECTION(infoId)); dispatch(deleteInfoSuccess(infoId)); return response.status; } catch (error) { - console.error(error); + toast.error(error.message || 'Failed to delete info collection.'); + return null; } }; }; - -// Action creator -export const deleteInfoSuccess = infoId => ({ - type: actions.DELETE_INFO_SUCCESS, - payload: infoId, -}); - -// Actions creators -export const fetchInfosSuccess = infoCollectionsData => ({ - type: actions.FETCH_INFOS_SUCCESS, - payload: { infoCollectionsData }, -}); - -export const updateInfoSuccess = updatedInfo => ({ - type: actions.UPDATE_INFO_SUCCESS, - payload: updatedInfo, -}); diff --git a/src/actions/leaderBoardData.js b/src/actions/leaderBoardData.js index 34f82b07d9..73f9f1c8ca 100644 --- a/src/actions/leaderBoardData.js +++ b/src/actions/leaderBoardData.js @@ -6,7 +6,6 @@ import { } from '../constants/leaderBoardData'; export const getLeaderboardData = userId => { - return async dispatch => { const url = ENDPOINTS.LEADER_BOARD(userId); const res = await httpService.get(url); @@ -16,7 +15,6 @@ export const getLeaderboardData = userId => { }; export const getOrgData = () => { - return async dispatch => { const url = ENDPOINTS.ORG_DATA; const res = await httpService.get(url); diff --git a/src/actions/mouseoverTextAction.js b/src/actions/mouseoverTextAction.js index ec4120f79c..b7122af7de 100644 --- a/src/actions/mouseoverTextAction.js +++ b/src/actions/mouseoverTextAction.js @@ -1,7 +1,7 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; - -import * as types from './../constants/mouseoverTextConstants'; +import * as types from '../constants/mouseoverTextConstants'; export const getMouseoverTextAction = payload => { return { @@ -16,7 +16,8 @@ export const getMouseoverText = () => async dispatch => { // console.log('Fetched mouseoverText data:', data); // Verify the fetched data return dispatch(getMouseoverTextAction(data)); } catch (error) { - console.log('Error fetching mouseoverText:', error); + toast.info('Error fetching mouseoverText:', error); + return null; } }; diff --git a/src/actions/notificationAction.js b/src/actions/notificationAction.js index d84b305c93..2ddd76a6a7 100644 --- a/src/actions/notificationAction.js +++ b/src/actions/notificationAction.js @@ -1,7 +1,6 @@ -import httpService from '../services/httpService'; +import axios from 'axios'; import { ApiEndpoint } from '../utils/URL'; import * as actionTypes from '../constants/notification'; -import axios from 'axios'; const APIEndpoint = ApiEndpoint; @@ -27,14 +26,14 @@ const constructErrorPayload = error => { return { status: response.status, - message: message, + message, }; }; /** * Retrieve all notifications for the given userId. - * @param {*} userId - * @returns + * @param {*} userId + * @returns */ export function getNotifications(userId) { return async dispatch => { @@ -47,7 +46,6 @@ export function getNotifications(userId) { payload: response.data, }); } catch (error) { - const errorPayload = constructErrorPayload(error); await dispatch({ type: actionTypes.FETCH_USER_NOTIFICATIONS_FAILURE, @@ -59,8 +57,8 @@ export function getNotifications(userId) { /** * Retrieve a list of unread notifications for the given userId. - * @param {*} userId - * @returns + * @param {*} userId + * @returns */ export function getUnreadUserNotifications(userId) { return async dispatch => { @@ -84,14 +82,15 @@ export function getUnreadUserNotifications(userId) { /** * Mark the notification as read and remove the record from redux if success. - * @param {*} notificationId - * @returns - * */ + * @param {*} notificationId + * @returns + * */ + export function markNotificationAsRead(notificationId) { return async dispatch => { dispatch({ type: actionTypes.MARK_NOTIFICATION_AS_READ_REQUEST }); try { - const response = await axios.post(`${APIEndpoint}/notification/markRead/${notificationId}`); + await axios.post(`${APIEndpoint}/notification/markRead/${notificationId}`); await dispatch({ type: actionTypes.MARK_NOTIFICATION_AS_READ_SUCCESS, @@ -107,15 +106,15 @@ export function markNotificationAsRead(notificationId) { }; } - /** * Reset error state in redux store for the notification component. - * */ + * */ + export function resetNotificationError() { return dispatch => { dispatch({ type: actionTypes.RESET_ERROR }); }; -} +} // Comment out unused functions // export function getSentNotifications() { @@ -156,7 +155,3 @@ export function resetNotificationError() { // }); // }; // } - - - - diff --git a/src/actions/ownerMessageAction.js b/src/actions/ownerMessageAction.js index c6332f5d73..dcbba6a871 100644 --- a/src/actions/ownerMessageAction.js +++ b/src/actions/ownerMessageAction.js @@ -1,7 +1,15 @@ import axios from 'axios'; import { ENDPOINTS } from '../utils/URL'; -import * as types from "../constants/ownerMessageConstants"; +import * as types from '../constants/ownerMessageConstants'; + +// action creator +export const updateOwnerMessageAction = payload => { + return { + type: types.UPDATE_OWNER_MESSAGE, + payload, + }; +}; // redux thunk functions export const getOwnerMessage = () => { @@ -15,10 +23,10 @@ export const getOwnerMessage = () => { } catch (error) { return error.response.data.error; } - } -} + }; +}; -export const updateOwnerMessage = (newMessage) => { +export const updateOwnerMessage = newMessage => { const url = ENDPOINTS.OWNERMESSAGE(); return async dispatch => { try { @@ -29,8 +37,8 @@ export const updateOwnerMessage = (newMessage) => { } catch (error) { return error.response.data.error; } - } -} + }; +}; export const deleteOwnerMessage = () => { const url = ENDPOINTS.OWNERMESSAGE(); @@ -38,18 +46,10 @@ export const deleteOwnerMessage = () => { try { const response = await axios.delete(url); const { ownerMessage } = response.data; - dispatch(updateOwnerMessageAction(ownerMessage)) + dispatch(updateOwnerMessageAction(ownerMessage)); return response; } catch (error) { return error.response.data.error; } - } -} - -// action creator -export const updateOwnerMessageAction = payload => { - return { - type: types.UPDATE_OWNER_MESSAGE, - payload, }; -} +}; diff --git a/src/actions/popupEditorAction.js b/src/actions/popupEditorAction.js index 3fc43bbf96..225c0867b3 100644 --- a/src/actions/popupEditorAction.js +++ b/src/actions/popupEditorAction.js @@ -6,6 +6,31 @@ import axios from 'axios'; import * as types from '../constants/popupEditorConstants'; import { ENDPOINTS } from '../utils/URL'; +/** ***************************************** + * ACTION CREATORS + ****************************************** */ + +export const setPopup = popupItems => { + return { + type: types.RECEIVE_POPUP, + popupItems, + }; +}; + +export const setCurrentPopup = currPopup => { + return { + type: types.CURRENT_POPUP, + currPopup, + }; +}; + +export const setPopupError = err => { + return { + type: types.FETCH_POPUP_ERROR, + err, + }; +}; + export const fetchAllPopupEditor = () => { const request = axios.get(ENDPOINTS.POPUP_EDITORS); return async dispatch => { @@ -13,7 +38,7 @@ export const fetchAllPopupEditor = () => { .then(res => { dispatch(setPopup(res.data)); }) - .catch(err => { + .catch(() => { dispatch(setPopupError()); }); }; @@ -59,28 +84,3 @@ export const backupPopupEditor = (popupId, popupContent, popupName) => { } }; }; - -/** ***************************************** - * ACTION CREATORS - ****************************************** */ - -export const setPopup = popupItems => { - return { - type: types.RECEIVE_POPUP, - popupItems, - }; -}; - -export const setCurrentPopup = currPopup => { - return { - type: types.CURRENT_POPUP, - currPopup, - }; -}; - -export const setPopupError = err => { - return { - type: types.FETCH_POPUP_ERROR, - err, - }; -}; diff --git a/src/actions/project.js b/src/actions/project.js index f885107050..6252cd87d5 100644 --- a/src/actions/project.js +++ b/src/actions/project.js @@ -2,6 +2,11 @@ import axios from 'axios'; import { ENDPOINTS } from '../utils/URL'; import { GET_PROJECT_BY_ID } from '../constants/project'; +export const setProjectDetail = data => ({ + type: GET_PROJECT_BY_ID, + payload: data, +}); + export const getProjectDetail = projectId => { const url = ENDPOINTS.PROJECT_BY_ID(projectId); return async dispatch => { @@ -16,8 +21,3 @@ export const getProjectDetail = projectId => { } }; }; - -export const setProjectDetail = data => ({ - type: GET_PROJECT_BY_ID, - payload: data, -}); diff --git a/src/actions/projectMembers.js b/src/actions/projectMembers.js index aa402a1ed1..51af98a244 100644 --- a/src/actions/projectMembers.js +++ b/src/actions/projectMembers.js @@ -4,8 +4,118 @@ ******************************************************************************* */ import axios from 'axios'; import * as types from '../constants/projectMembership'; -import { searchWithAccent } from 'utils/search'; import { ENDPOINTS } from '../utils/URL'; + +/** ***************************************** + * PLAIN OBJ ACTIONS + ****************************************** */ + +/** + * Set a flag that fetching Members + */ +export const setMemberStart = () => { + return { + type: types.FETCH_MEMBERS_START, + }; +}; + +/** + * set Members in store + * @param payload : Members [] + */ +export const setMembers = members => { + return { + type: types.RECEIVE_MEMBERS, + members, + }; +}; + +/** + * Error when setting project + * @param payload : error status code + */ +export const setMembersError = err => { + return { + type: types.FETCH_MEMBERS_ERROR, + err, + }; +}; + +/** + * Set a flag that finding Members + */ +export const findUsersStart = () => { + return { + type: types.FIND_USERS_START, + }; +}; + +/** + * set Users in store + * @param payload : Users [] + */ +export const foundUsers = users => { + return { + type: types.FOUND_USERS, + users, + }; +}; + +/** + * Error when setting project + * @param payload : error status code + */ +export const findUsersError = err => { + return { + type: types.FIND_USERS_ERROR, + err, + }; +}; + +/** + * add new member to project + * @param member : {} + */ +export const assignNewMember = member => { + return { + type: types.ADD_NEW_MEMBER, + member, + }; +}; + +/** + * remove a member from project + * @param userId : _id + */ +export const deleteMember = userId => { + return { + type: types.DELETE_MEMBER, + userId, + }; +}; + +/** + * remove found user after assign + * @param userId : _id + */ +export const removeFoundUser = userId => { + return { + type: types.REMOVE_FOUND_USER, + userId, + }; +}; + +/** + * Error when add new member + * @param payload : error status code + */ +export const addNewMemberError = err => { + return { + type: types.ADD_NEW_MEMBER_ERROR, + err, + }; +}; + /** ***************************************** * ACTION CREATORS ****************************************** */ @@ -18,10 +128,8 @@ export const getAllUserProfiles = () => { .then(res => { const { members } = getState().projectMembers; const users = res.data.map(user => { - if (!members.find(member => member._id === user._id)) { - return (user = { ...user, assigned: false }); - } - return (user = { ...user, assigned: true }); + const isAssigned = members.some(member => member._id === user._id); + return { ...user, assigned: isAssigned }; }); // console.log(users); dispatch(foundUsers(users)); @@ -72,40 +180,35 @@ export const getAllUserProfiles = () => { // }; // }; -//Done By Mohammad +// Done By Mohammad export const findUserProfiles = keyword => { // Creates an array containing the first and last name and filters out whitespace - const fullNameRegex = keyword.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); // Escape special characters + const fullNameRegex = keyword.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); // Escape special characters - return async (dispatch, getState) => { - try { - const response = await axios.get( - ENDPOINTS.USER_PROFILE_BY_FULL_NAME(fullNameRegex), - ); + return async (dispatch, getState) => { + try { + const response = await axios.get(ENDPOINTS.USER_PROFILE_BY_FULL_NAME(fullNameRegex)); - await dispatch(findUsersStart()); - if (keyword !== '') { - let users = response.data; - const { members } = getState().projectMembers; - users = users.map(user => { - if (!members.find(member => member._id === user._id)) { - return (user = { ...user, assigned: false }); - } - return (user = { ...user, assigned: true }); - }); - dispatch(foundUsers(users)); - } else { - dispatch(foundUsers([])); - } - } catch (error) { - dispatch(foundUsers([])); - dispatch(findUsersError(error)); - } - }; + await dispatch(findUsersStart()); + if (keyword !== '') { + let users = response.data; + const { members } = getState().projectMembers; + users = users.map(user => { + const isAssigned = members.some(member => member._id === user._id); + return { ...user, assigned: isAssigned }; + }); + dispatch(foundUsers(users)); + } else { + dispatch(foundUsers([])); + } + } catch (error) { + dispatch(foundUsers([])); + dispatch(findUsersError(error)); + } + }; }; - /** * Call API to get all members */ @@ -161,7 +264,7 @@ export const assignProject = (projectId, userId, operation, firstName, lastName) return async dispatch => { request - .then(res => { + .then(() => { // console.log("RES", res); if (operation === 'Assign') { dispatch( @@ -182,113 +285,3 @@ export const assignProject = (projectId, userId, operation, firstName, lastName) }); }; }; - -/** ***************************************** - * PLAIN OBJ ACTIONS - ****************************************** */ - -/** - * Set a flag that fetching Members - */ -export const setMemberStart = () => { - return { - type: types.FETCH_MEMBERS_START, - }; -}; - -/** - * set Members in store - * @param payload : Members [] - */ -export const setMembers = members => { - return { - type: types.RECEIVE_MEMBERS, - members, - }; -}; - -/** - * Error when setting project - * @param payload : error status code - */ -export const setMembersError = err => { - return { - type: types.FETCH_MEMBERS_ERROR, - err, - }; -}; - -/** - * Set a flag that finding Members - */ -export const findUsersStart = () => { - return { - type: types.FIND_USERS_START, - }; -}; - -/** - * set Users in store - * @param payload : Users [] - */ -export const foundUsers = users => { - return { - type: types.FOUND_USERS, - users, - }; -}; - -/** - * Error when setting project - * @param payload : error status code - */ -export const findUsersError = err => { - return { - type: types.FIND_USERS_ERROR, - err, - }; -}; - -/** - * add new member to project - * @param member : {} - */ -export const assignNewMember = member => { - return { - type: types.ADD_NEW_MEMBER, - member, - }; -}; - -/** - * remove a member from project - * @param userId : _id - */ -export const deleteMember = userId => { - return { - type: types.DELETE_MEMBER, - userId, - }; -}; - -/** - * remove found user after assign - * @param userId : _id - */ -export const removeFoundUser = userId => { - return { - type: types.REMOVE_FOUND_USER, - userId, - }; -}; - -/** - * Error when add new member - * @param payload : error status code - */ -export const addNewMemberError = err => { - return { - type: types.ADD_NEW_MEMBER_ERROR, - err, - }; -}; diff --git a/src/actions/projects.js b/src/actions/projects.js index 0a4d88300b..993bceaeee 100644 --- a/src/actions/projects.js +++ b/src/actions/projects.js @@ -2,6 +2,84 @@ import axios from 'axios'; import * as types from '../constants/projects'; import { ENDPOINTS } from '../utils/URL'; +/** ***************************************** + * PLAIN OBJECT ACTIONS + ****************************************** */ + +/** + * Set a flag that fetching projects + */ +const setProjectsStart = () => ({ + type: types.FETCH_PROJECTS_START, +}); + +/** + * set Projects in store + * @param projects: projects + * @param status: status code + */ +const setProjectsSuccess = ({ projects, status }) => ({ + type: types.FETCH_PROJECTS_SUCCESS, + projects, + status, +}); + +/** + * Error when setting project + * @param payload: error status code + */ +const setProjectsError = ({ status, error }) => ({ + type: types.FETCH_PROJECTS_ERROR, + status, + error, +}); + +/** + * Add new project to store + * @param payload : new project + * @param status: status code + * @param error: error message + */ +const addNewProject = ({ newProject, status, error }) => ({ + type: types.ADD_NEW_PROJECT, + newProject, + status, + error, +}); + +/** + * Update project in store + * @param updatedProject: updated project + * @param status: status code + * @param error: error message + */ +// const updateProject = (projectId, projectName, category, isActive, status, error) => { +const updateProject = ({ updatedProject, status, error }) => ({ + type: types.UPDATE_PROJECT, + updatedProject, + status, + error, +}); + +/** + * Remove project from store + * @param projectId: id of project to remove + * @param status: status code + */ +const removeProject = ({ projectId, status, error }) => ({ + type: types.DELETE_PROJECT, + projectId, + status, + error, +}); + +/** + * Clear error in store + */ +export const clearError = () => ({ + type: types.CLEAR_ERROR, +}); + /** ***************************************** * ACTION CREATORS ****************************************** */ @@ -12,7 +90,8 @@ import { ENDPOINTS } from '../utils/URL'; export const fetchAllProjects = () => { return async dispatch => { const url = ENDPOINTS.PROJECTS; - let status, error; + let status; + let error; dispatch(setProjectsStart()); try { const res = await axios.get(url); @@ -35,11 +114,12 @@ export const fetchAllProjects = () => { export const postNewProject = (projectName, projectCategory) => { return async dispatch => { const url = ENDPOINTS.PROJECTS; - let status, error; + let status; + let error; dispatch(setProjectsStart()); try { const res = await axios.post(url, { projectName, projectCategory }); - const _id = res.data._id; + const { _id } = res.data; status = res.status; const newProject = { _id, @@ -53,9 +133,9 @@ export const postNewProject = (projectName, projectCategory) => { } catch (err) { const errorInfo = { status: err.response ? err.response.status : 500, - error: err.response ? err.response.data : 'Network error' + error: err.response ? err.response.data : 'Network error', }; - dispatch(setProjectsError(errorInfo)); + dispatch(setProjectsError(errorInfo)); throw error; } }; @@ -64,7 +144,8 @@ export const postNewProject = (projectName, projectCategory) => { export const modifyProject = updatedProject => { return async dispatch => { const url = ENDPOINTS.PROJECT + updatedProject._id; - let status, error; + let status; + let error; try { const res = await axios.put(url, updatedProject); status = res.status; @@ -84,7 +165,8 @@ export const modifyProject = updatedProject => { export const deleteProject = projectId => { return async dispatch => { const url = ENDPOINTS.PROJECT + projectId; - let status, error; + let status; + let error; try { const res = await axios.delete(url); status = res.status; @@ -96,81 +178,3 @@ export const deleteProject = projectId => { } }; }; - -/** ***************************************** - * PLAIN OBJECT ACTIONS - ****************************************** */ - -/** - * Set a flag that fetching projects - */ -const setProjectsStart = () => ({ - type: types.FETCH_PROJECTS_START, -}); - -/** - * set Projects in store - * @param projects: projects - * @param status: status code - */ -const setProjectsSuccess = ({ projects, status }) => ({ - type: types.FETCH_PROJECTS_SUCCESS, - projects, - status, -}); - -/** - * Error when setting project - * @param payload: error status code - */ -const setProjectsError = ({ status, error }) => ({ - type: types.FETCH_PROJECTS_ERROR, - status, - error, -}); - -/** - * Add new project to store - * @param payload : new project - * @param status: status code - * @param error: error message - */ -const addNewProject = ({ newProject, status, error }) => ({ - type: types.ADD_NEW_PROJECT, - newProject, - status, - error, -}); - -/** - * Update project in store - * @param updatedProject: updated project - * @param status: status code - * @param error: error message - */ -// const updateProject = (projectId, projectName, category, isActive, status, error) => { -const updateProject = ({ updatedProject, status, error }) => ({ - type: types.UPDATE_PROJECT, - updatedProject, - status, - error, -}); - -/** - * Remove project from store - * @param projectId: id of project to remove - * @param status: status code - */ -const removeProject = ({ projectId, status, error }) => ({ - type: types.DELETE_PROJECT, - projectId, - status, - error, -}); - -/** - * Clear error in store - */ -export const clearError = () => ({ - type: types.CLEAR_ERROR, -}); \ No newline at end of file diff --git a/src/actions/reasonsActions.js b/src/actions/reasonsActions.js index dfd3f933d6..199cf89416 100644 --- a/src/actions/reasonsActions.js +++ b/src/actions/reasonsActions.js @@ -1,43 +1,59 @@ import axios from 'axios'; -import { ENDPOINTS } from 'utils/URL'; +import { ENDPOINTS } from '../utils/URL'; export async function addReason(userId, reasonData) { try { const url = ENDPOINTS.CREATEREASON(userId); - const response = await axios.post(url, { userId: userId, reasonData: reasonData }); - return Promise.resolve(response) + const response = await axios.post(url, { userId, reasonData }); + return Promise.resolve(response); } catch (error) { - return {message: error.response.data.message, errorCode: error.response.data.message, status: error.response.status} + return { + message: error.response.data.message, + errorCode: error.response.data.message, + status: error.response.status, + }; } } -export async function getReasonByDate(userId, queryDate){ - try { - const url = ENDPOINTS.GETSINGLEREASONBYID(userId); - const response = await axios.get(url, {params: {queryDate: queryDate }}); - return Promise.resolve(response) - } catch (error) { - return {message: error.response.data.message, errorCode: error.response.data.message, status: error.response.status} - } +export async function getReasonByDate(userId, queryDate) { + try { + const url = ENDPOINTS.GETSINGLEREASONBYID(userId); + const response = await axios.get(url, { params: { queryDate } }); + return Promise.resolve(response); + } catch (error) { + return { + message: error.response.data.message, + errorCode: error.response.data.message, + status: error.response.status, + }; + } } export async function patchReason(userId, reasonData) { - try { - const url = ENDPOINTS.PATCHUSERREASONBYID(userId); - const response = await axios.patch(url, { userId: userId, reasonData: reasonData }); - return Promise.resolve(response) - } catch (error) { - return {message: error.response.data.message, errorCode: error.response.data.message, status: error.response.status} - } + try { + const url = ENDPOINTS.PATCHUSERREASONBYID(userId); + const response = await axios.patch(url, { userId, reasonData }); + return Promise.resolve(response); + } catch (error) { + return { + message: error.response.data.message, + errorCode: error.response.data.message, + status: error.response.status, + }; } +} // gets all scheduled reasons - Sucheta -export async function getAllReasons(userId){ - try{ +export async function getAllReasons(userId) { + try { const url = ENDPOINTS.GETALLUSERREASONS(userId); const response = await axios.get(url); - return Promise.resolve(response) - }catch(error){ - return {message: error.response.data.message, errorCode:error.response.data.message, status: error.repsonse.status} + return Promise.resolve(response); + } catch (error) { + return { + message: error.response.data.message, + errorCode: error.response.data.message, + status: error.repsonse.status, + }; } -} \ No newline at end of file +} diff --git a/src/actions/role.js b/src/actions/role.js index 7fbb0dc8f7..41e708e950 100644 --- a/src/actions/role.js +++ b/src/actions/role.js @@ -1,7 +1,21 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; import * as types from '../constants/role'; +export const setRoleStart = () => { + return { + type: types.FETCH_ROLES_START, + }; +}; + +export const setRoleError = payload => { + return { + type: types.FETCH_ROLES_ERROR, + payload, + }; +}; + export const fetchAllRoles = roles => { return { type: types.RECEIVE_ROLES, @@ -44,27 +58,13 @@ export const addNewRole = newRole => { export const updateRole = (roleId, updatedRole) => { return async dispatch => { try { - const res = await axios.patch(ENDPOINTS.ROLES_BY_ID(roleId), updatedRole); + await axios.patch(ENDPOINTS.ROLES_BY_ID(roleId), updatedRole); dispatch(modifyRole(updatedRole)); return 0; } catch (err) { dispatch(setRoleError()); - console.log(err); + toast.error(err.message || 'Failed to update role.'); return 1; } - dispatch(modifyRole(updatedRole)); }; }; - -export const setRoleStart = () => { - return { - type: types.FETCH_ROLES_START, - }; -}; - -export const setRoleError = payload => { - return { - type: types.FETCH_ROLES_ERROR, - payload, - }; -}; \ No newline at end of file diff --git a/src/actions/rolePermissionPresets.js b/src/actions/rolePermissionPresets.js index 7b47e07ae9..d01fa89df9 100644 --- a/src/actions/rolePermissionPresets.js +++ b/src/actions/rolePermissionPresets.js @@ -1,8 +1,9 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; -import * as types from "../constants/rolePermissionPresets"; +import * as types from '../constants/rolePermissionPresets'; -export const fetchPresets = (presets) => { +export const fetchPresets = presets => { return { type: types.RECEIVE_PRESETS, presets, @@ -30,7 +31,7 @@ export const updatePreset = payload => { }; }; -export const getPresetsByRole = (roleName) => async dispatch => { +export const getPresetsByRole = roleName => async dispatch => { const URL = ENDPOINTS.PRESETS_BY_ID(roleName); const { data } = await axios.get(URL); return dispatch(fetchPresets(data)); @@ -40,40 +41,41 @@ export const createNewPreset = newPreset => { return async dispatch => { try { const res = await axios.post(ENDPOINTS.PRESETS(), newPreset); - if (res.status === 201){ + if (res.status === 201) { dispatch(postNewPreset(res.data.newPreset)); } return 0; } catch (error) { - console.log(error) + toast.error(error); return 1; } }; }; -export const updatePresetById = (updatedPreset) => { +export const updatePresetById = updatedPreset => { return async dispatch => { try { const res = await axios.put(ENDPOINTS.PRESETS_BY_ID(updatedPreset._id), updatedPreset); - if (res.status === 200){ + if (res.status === 200) { dispatch(updatePreset(updatedPreset)); } } catch (err) { - console.log(err); + toast.info(err); } }; }; -export const deletePresetById = (presetId) => { +export const deletePresetById = presetId => { return async dispatch => { try { const res = await axios.delete(ENDPOINTS.PRESETS_BY_ID(presetId)); - if (res.status === 200){ + if (res.status === 200) { dispatch(deletePreset(presetId)); return 0; } + return 1; } catch (error) { - console.log(error); + toast.info(error); return 1; } }; diff --git a/src/actions/sendEmails.js b/src/actions/sendEmails.js index 6ff843a9d3..4db5295ab2 100644 --- a/src/actions/sendEmails.js +++ b/src/actions/sendEmails.js @@ -10,7 +10,7 @@ export const sendEmail = (to, subject, html) => { return async () => { try { const response = await axios.post(url, { to, subject, html }); - console.log('Email sent successfully:', response); + toast.info('Email sent successfully:', response); // Display a success toast toast.success('Email successfully sent', { @@ -18,7 +18,7 @@ export const sendEmail = (to, subject, html) => { autoClose: 3000, // Close the toast after 3 seconds (adjust as needed) }); } catch (error) { - console.error('Error sending email:', error); + toast.error('Error sending email:', error); // Display an error toast toast.error('Error sending email', { @@ -35,7 +35,7 @@ export const broadcastEmailsToAll = (subject, html) => { return async () => { try { const response = await axios.post(url, { subject, html }); - console.log('Email sent successfully:', response); + toast.info('Email sent successfully:', response); // Display a success toast toast.success('Email successfully sent', { @@ -43,7 +43,7 @@ export const broadcastEmailsToAll = (subject, html) => { autoClose: 3000, // Close the toast after 3 seconds (adjust as needed) }); } catch (error) { - console.error('Error sending email:', error); + toast.error('Error sending email:', error); // Display an error toast toast.error('Error sending email', { @@ -54,13 +54,13 @@ export const broadcastEmailsToAll = (subject, html) => { }; }; -export const updateEmailSubscription = (subscription=true) => { +export const updateEmailSubscription = (subscription = true) => { const url = ENDPOINTS.UPDATE_EMAIL_SUBSCRIPTION; return async () => { try { - const response = await axios.post(url, { subscription}); - console.log('Email sent successfully:', response); + const response = await axios.post(url, { subscription }); + toast.info('Email sent successfully:', response); // Display a success toast toast.success('Successfully changed email subcription', { @@ -68,7 +68,7 @@ export const updateEmailSubscription = (subscription=true) => { autoClose: 3000, // Close the toast after 3 seconds (adjust as needed) }); } catch (error) { - console.error('Error sending email:', error); + toast.error('Error sending email:', error); // Display an error toast toast.error('Error sending request', { @@ -79,13 +79,13 @@ export const updateEmailSubscription = (subscription=true) => { }; }; -export const addNonHgnUserEmailSubscription = (email='') => { +export const addNonHgnUserEmailSubscription = (email = '') => { const url = ENDPOINTS.NON_HGN_EMAIL_SUBSCRIPTION; return async () => { try { - const response = await axios.post(url, { email}); - console.log('Email sent successfully:', response); + const response = await axios.post(url, { email }); + toast.info('Email sent successfully:', response); // Display a success toast toast.success('Send confirmation to email', { @@ -93,7 +93,7 @@ export const addNonHgnUserEmailSubscription = (email='') => { autoClose: 3000, // Close the toast after 3 seconds (adjust as needed) }); } catch (error) { - console.error('Error sending email:', error); + toast.error('Error sending email:', error); // Display an error toast toast.error('Email already exists or invalid', { @@ -104,7 +104,6 @@ export const addNonHgnUserEmailSubscription = (email='') => { }; }; - export const confirmNonHgnUserEmailSubscription = async (token = '') => { const url = ENDPOINTS.CONFIRM_EMAIL_SUBSCRIPTION; @@ -119,7 +118,7 @@ export const confirmNonHgnUserEmailSubscription = async (token = '') => { return { success: true, data: response.data }; } catch (error) { - console.error('Error sending email:', error); + toast.error('Error sending email:', error); // Display an error toast // toast.error('Error sending request', { @@ -127,11 +126,10 @@ export const confirmNonHgnUserEmailSubscription = async (token = '') => { // autoClose: 3000, // }); - return { success: false, error: error }; + return { success: false, error }; } }; - export const removeNonHgnUserEmailSubscription = async (email = '') => { const url = ENDPOINTS.REMOVE_EMAIL_SUBSCRIPTION; @@ -146,7 +144,7 @@ export const removeNonHgnUserEmailSubscription = async (email = '') => { return { success: true, data: response.data }; } catch (error) { - console.error('Error sending email:', error); + toast.error('Error sending email:', error); // Display an error toast // toast.error('Error sending request', { @@ -154,6 +152,6 @@ export const removeNonHgnUserEmailSubscription = async (email = '') => { // autoClose: 3000, // }); - return { success: false, error: error }; + return { success: false, error }; } }; diff --git a/src/actions/task.js b/src/actions/task.js index 6f6a71e253..8e447aaf20 100644 --- a/src/actions/task.js +++ b/src/actions/task.js @@ -3,6 +3,7 @@ * Author: Henry Ng - 03/20/20 ******************************************************************************* */ import axios from 'axios'; +import { toast } from 'react-toastify'; import moment from 'moment'; import { fetchTeamMembersTaskSuccess, @@ -11,31 +12,109 @@ import { fetchTeamMembersDataBegin, fetchTeamMembersDataError, deleteTaskNotificationSuccess, - deleteTaskNotificationBegin, -} from 'components/TeamMemberTasks/actions'; -import { createTaskEditSuggestionHTTP } from 'components/TaskEditSuggestions/service'; +} from '../components/TeamMemberTasks/actions'; +import { createTaskEditSuggestionHTTP } from '../components/TaskEditSuggestions/service'; import * as types from '../constants/task'; import { ENDPOINTS } from '../utils/URL'; import { createOrUpdateTaskNotificationHTTP } from './taskNotification'; -import { fetchTaskEditSuggestions } from 'components/TaskEditSuggestions/thunks'; +import { fetchTaskEditSuggestions } from '../components/TaskEditSuggestions/thunks'; -const selectFetchTeamMembersTaskData = state => state.auth.user.userid; const selectUserId = state => state.auth.user.userid; const selectUpdateTaskData = (state, taskId) => state.tasks.taskItems.find(({ _id }) => _id === taskId); -export const fetchTeamMembersTask = (displayUserId) => async (dispatch) => { - try { - dispatch(fetchTeamMembersDataBegin()); +/** + * Set a flag that fetching Task + */ +export const setTasksStart = () => { + return { + type: types.FETCH_TASKS_START, + }; +}; - const { data: usersWithTasks } = await axios.get(ENDPOINTS.TEAM_MEMBER_TASKS(displayUserId)); +/** + * set Task in store + * @param payload : Task [] + */ +export const setTasks = (taskItems, level, mother) => { + return { + type: types.RECEIVE_TASKS, + taskItems, + level, + mother, + }; +}; - dispatch(fetchTeamMembersTaskSuccess({ usersWithTasks })); +export const emptyTaskItems = () => { + return { + type: types.EMPTY_TASK_ITEMS, + }; +}; - await dispatch(fetchTeamMembersTimeEntries()); - } catch (error) { - dispatch(fetchTeamMembersDataError()); - } +/** + * Error when setting project + * @param payload : error status code + */ +export const setTasksError = err => { + return { + type: types.FETCH_TASKS_ERROR, + err, + }; +}; + +export const setAddTaskError = err => { + return { + type: types.ADD_NEW_TASK_ERROR, + err, + }; +}; + +export const postNewTask = (newTask, status) => { + return { + type: types.ADD_NEW_TASK, + newTask, + status, + }; +}; + +export const putUpdatedTask = (updatedTask, taskId, status) => { + return { + type: types.UPDATE_TASK, + updatedTask, + taskId, + status, + }; +}; + +export const swapTasks = (tasks, status) => { + return { + type: types.SWAP_TASKS, + tasks, + status, + }; +}; + +export const updateNums = updatedList => { + toast.info('updated list', updatedList); + return { + type: types.UPDATE_NUMS, + updatedList, + }; +}; + +export const removeTask = (taskId, status) => { + return { + type: types.DELETE_TASK, + taskId, + status, + }; +}; + +export const saveTmpTask = taskId => { + return { + type: types.COPY_TASK, + taskId, + }; }; export const fetchTeamMembersTimeEntries = () => async (dispatch, getState) => { @@ -52,12 +131,12 @@ export const fetchTeamMembersTimeEntries = () => async (dispatch, getState) => { .format('YYYY-MM-DD'); // only request for users with task - const userIds = teamMemberTasks.usersWithTasks.map(user => user.personId) + const userIds = teamMemberTasks.usersWithTasks.map(user => user.personId); const { data: usersWithTimeEntries } = await axios.post(ENDPOINTS.TIME_ENTRIES_USER_LIST, { - users: userIds, - fromDate, - toDate + users: userIds, + fromDate, + toDate, }); dispatch(fetchTeamMembersTimeEntriesSuccess({ usersWithTimeEntries })); @@ -66,7 +145,21 @@ export const fetchTeamMembersTimeEntries = () => async (dispatch, getState) => { } }; -export const editTeamMemberTimeEntry = (newDate) => async (dispatch) => { +export const fetchTeamMembersTask = displayUserId => async dispatch => { + try { + dispatch(fetchTeamMembersDataBegin()); + + const { data: usersWithTasks } = await axios.get(ENDPOINTS.TEAM_MEMBER_TASKS(displayUserId)); + + dispatch(fetchTeamMembersTaskSuccess({ usersWithTasks })); + + await dispatch(fetchTeamMembersTimeEntries()); + } catch (error) { + dispatch(fetchTeamMembersDataError()); + } +}; + +export const editTeamMemberTimeEntry = newDate => async dispatch => { const { userProfile, ...timeEntry } = newDate; const timeEntryURL = ENDPOINTS.TIME_ENTRY_CHANGE(timeEntry._id); try { @@ -78,15 +171,12 @@ export const editTeamMemberTimeEntry = (newDate) => async (dispatch) => { }; // TODO: TeamMemberTasks.jsx dispatch -export const deleteTaskNotification = (userId, taskId, taskNotificationId) => async ( - dispatch, - getState, -) => { +export const deleteTaskNotification = (userId, taskId, taskNotificationId) => async dispatch => { try { // dispatch(deleteTaskNotificationBegin()); - const res = await axios.delete(ENDPOINTS.DELETE_TASK_NOTIFICATION_BY_USER_ID(taskId, userId)); + await axios.delete(ENDPOINTS.DELETE_TASK_NOTIFICATION_BY_USER_ID(taskId, userId)); - //const res = await axios.delete(ENDPOINTS.DELETE_TASK_NOTIFICATION(taskNotificationId)); + // const res = await axios.delete(ENDPOINTS.DELETE_TASK_NOTIFICATION(taskNotificationId)); dispatch(deleteTaskNotificationSuccess({ userId, taskId, taskNotificationId })); // window.location.reload(false); } catch (error) { @@ -95,68 +185,69 @@ export const deleteTaskNotification = (userId, taskId, taskNotificationId) => as }; export const deleteChildrenTasks = taskId => { - return async (dispatch, getState) => { - let status = 200; - try { - await axios.post(ENDPOINTS.DELETE_CHILDREN(taskId)); - } catch (error) { - console.log(error); - } -}}; + return async () => { + try { + await axios.post(ENDPOINTS.DELETE_CHILDREN(taskId)); + } catch (error) { + toast.info(error); + } + }; +}; -export const addNewTask = (newTask, wbsId, pageLoadTime) => async (dispatch, getState) => { +export const addNewTask = (newTask, wbsId, pageLoadTime) => async dispatch => { let status = 200; - let _id = null; let task = {}; + try { const wbs = await axios.get(ENDPOINTS.TASK_WBS(wbsId)); + if (Date.parse(wbs.data.modifiedDatetime) > pageLoadTime) { dispatch(setAddTaskError('outdated')); - const res = await axios.post(ENDPOINTS.TASK(wbsId), newTask); - dispatch(postNewTask(res.data, status)); - _id = res.data._id; - status = res.status; - task = res.data; - const userIds = task.resources.map(resource => resource.userID); - await createOrUpdateTaskNotificationHTTP(task._id, {}, userIds); - } else { - const res = await axios.post(ENDPOINTS.TASK(wbsId), newTask); - dispatch(postNewTask(res.data, status)); - _id = res.data._id; - status = res.status; - task = res.data; - const userIds = task.resources.map(resource => resource.userID); - await createOrUpdateTaskNotificationHTTP(task._id, {}, userIds); } + + const res = await axios.post(ENDPOINTS.TASK(wbsId), newTask); + task = res.data; + status = res.status; + dispatch(postNewTask(task, status)); + + const userIds = task.resources.map(resource => resource.userID); + await createOrUpdateTaskNotificationHTTP(task._id, {}, userIds); + return task._id; } catch (error) { status = 400; + toast.error('Failed to add new task'); + return null; } - newTask._id = _id; }; -export const updateTask = (taskId, updatedTask, hasPermission, prevTask) => async (dispatch, getState) => { +export const updateTask = (taskId, updatedTask, hasPermission, prevTask) => async ( + dispatch, + getState, +) => { let status = 200; try { const state = getState(); - - let oldTask - if(prevTask){ - oldTask = prevTask - }else{ + + let oldTask; + if (prevTask) { + oldTask = prevTask; + } else { oldTask = selectUpdateTaskData(state, taskId); } if (hasPermission) { await axios.put(ENDPOINTS.TASK_UPDATE(taskId), updatedTask); const userIds = updatedTask.resources.map(resource => resource.userID); - await createOrUpdateTaskNotificationHTTP(taskId, oldTask, userIds); + await createOrUpdateTaskNotificationHTTP(taskId, oldTask, userIds); } else { - await createTaskEditSuggestionHTTP(taskId, selectUserId(state), oldTask, updatedTask).then(() => { - dispatch(fetchTaskEditSuggestions()) - }); + await createTaskEditSuggestionHTTP(taskId, selectUserId(state), oldTask, updatedTask).then( + () => { + dispatch(fetchTaskEditSuggestions()); + }, + ); } } catch (error) { // dispatch(fetchTeamMembersTaskError()); - console.log(error); + toast.info(error); status = 400; } // TODO: DISPATCH TO TASKEDITSUGGESETIONS REDUCER TO UPDATE STATE @@ -165,31 +256,35 @@ export const updateTask = (taskId, updatedTask, hasPermission, prevTask) => asyn export const importTask = (newTask, wbsId) => { const url = ENDPOINTS.TASK_IMPORT(wbsId); - return async dispatch => { + return async () => { let status = 200; let _id = null; let task = {}; try { const res = await axios.post(url, { list: newTask }); + // eslint-disable-next-line no-unused-vars _id = res.data._id; status = res.status; + // eslint-disable-next-line no-unused-vars task = res.data; } catch (err) { - console.log('TRY CATCH ERR', err); + toast.info('TRY CATCH ERR', err); + // eslint-disable-next-line no-unused-vars status = 400; } }; }; export const updateNumList = (wbsId, list) => { - const url = `${ENDPOINTS.TASKS_UPDATE }/num`; + const url = `${ENDPOINTS.TASKS_UPDATE}/num`; return async dispatch => { let status = 200; try { const res = await axios.put(url, { wbsId, nums: list }); status = res.status; } catch (err) { + // eslint-disable-next-line no-unused-vars status = 400; } await dispatch(updateNums(list)); @@ -227,6 +322,7 @@ export const deleteTask = (taskId, mother) => { try { await axios.post(url); } catch (err) { + // eslint-disable-next-line no-unused-vars status = 400; } dispatch(emptyTaskItems()); @@ -239,97 +335,3 @@ export const copyTask = taskId => { await dispatch(saveTmpTask(taskId)); }; }; - -/** - * Set a flag that fetching Task - */ -export const setTasksStart = () => { - return { - type: types.FETCH_TASKS_START, - }; -}; - -/** - * set Task in store - * @param payload : Task [] - */ -export const setTasks = (taskItems, level, mother) => { - return { - type: types.RECEIVE_TASKS, - taskItems, - level, - mother, - }; -}; - -export const emptyTaskItems = () => { - return { - type: types.EMPTY_TASK_ITEMS, - }; -}; - -/** - * Error when setting project - * @param payload : error status code - */ -export const setTasksError = err => { - return { - type: types.FETCH_TASKS_ERROR, - err, - }; -}; - -export const setAddTaskError = err => { - return { - type: types.ADD_NEW_TASK_ERROR, - err, - }; -}; - -export const postNewTask = (newTask, status) => { - return { - type: types.ADD_NEW_TASK, - newTask, - status, - }; -}; - -export const putUpdatedTask = (updatedTask, taskId, status) => { - return { - type: types.UPDATE_TASK, - updatedTask, - taskId, - status, - }; -}; - -export const swapTasks = (tasks, status) => { - return { - type: types.SWAP_TASKS, - tasks, - status, - }; -}; - -export const updateNums = updatedList => { - console.log('updated list', updatedList); - return { - type: types.UPDATE_NUMS, - updatedList, - }; -}; - -export const removeTask = (taskId, status) => { - return { - type: types.DELETE_TASK, - taskId, - status, - }; -}; - -export const saveTmpTask = taskId => { - return { - type: types.COPY_TASK, - taskId, - }; -}; diff --git a/src/actions/taskNotification.js b/src/actions/taskNotification.js index d97a517023..9a95a66faf 100644 --- a/src/actions/taskNotification.js +++ b/src/actions/taskNotification.js @@ -1,19 +1,26 @@ import axios from 'axios'; -import httpService from '../services/httpService'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; +import { + createOrUpdateTaskNotificationSuccess, + createOrUpdateTaskNotificationBegin, + createOrUpdateTaskNotificationError, +} from '../components/TeamMemberTasks/actions'; +import { selectFetchTeamMembersTaskData } from '../components/TaskEditSuggestions/thunks'; export const createOrUpdateTaskNotificationHTTP = async (taskId, oldTask, userIds) => { try { const payload = { oldTask, userIds }; await axios.post(ENDPOINTS.CREATE_OR_UPDATE_TASK_NOTIFICATION(taskId), payload); } catch (error) { - console.log(`Error on create or update task notification with error: ${ error}`); + toast.info(`Error on create or update task notification with error: ${error}`); } }; export const createOrUpdateTaskNotification = () => async (dispatch, getState) => { try { const state = getState(); + // eslint-disable-next-line no-unused-vars const userIds = selectFetchTeamMembersTaskData(state); // TODO: get userIds dispatch(createOrUpdateTaskNotificationBegin()); // what should endpoint return? want create/update to behave the same diff --git a/src/actions/team.js b/src/actions/team.js index 79897a3869..404b6ebf54 100644 --- a/src/actions/team.js +++ b/src/actions/team.js @@ -1,17 +1,37 @@ import moment from 'moment'; import { uniqBy } from 'lodash'; import axios from 'axios'; +import { toast } from 'react-toastify'; import httpService from '../services/httpService'; import { FETCH_TEAMS_START, RECEIVE_TEAMS, FETCH_TEAMS_ERROR } from '../constants/teams'; import { ENDPOINTS } from '../utils/URL'; import { GET_TEAM_BY_ID } from '../constants/team'; +const setTeamsStart = () => ({ + type: FETCH_TEAMS_START, +}); + +const setTeams = payload => ({ + type: RECEIVE_TEAMS, + payload, +}); + +const setTeamsError = payload => ({ + type: FETCH_TEAMS_ERROR, + payload, +}); + +export const setTeamDetail = data => ({ + type: GET_TEAM_BY_ID, + payload: data, +}); + export function getUserTeamMembers1(userId) { const request = httpService.get(ENDPOINTS.USER_TEAM(userId)); return dispatch => { request.then(({ data }) => { - console.log('data', data); + toast.info('data', data); dispatch({ type: 'GET_USER_TEAM_MEMBERS', payload: data, @@ -22,7 +42,8 @@ export function getUserTeamMembers1(userId) { export const getUserTeamMembers = userId => { const url = ENDPOINTS.USER_TEAM(userId); - return async dispatch => { + return async () => { + // eslint-disable-next-line no-unused-vars const res = await httpService.get(url); }; }; @@ -40,7 +61,7 @@ export const fetchAllManagingTeams = (userId, managingTeams) => async dispatch = try { const teamMembersResponses = await Promise.all(teamMembersPromises); - for (let i = 0; i < managingTeams.length; i++) { + for (let i = 0; i < managingTeams.length; i += 1) { allManagingTeams[i] = { ...managingTeams[i], members: teamMembersResponses[i].data, @@ -48,29 +69,35 @@ export const fetchAllManagingTeams = (userId, managingTeams) => async dispatch = allMembers = allMembers.concat(teamMembersResponses[i].data); } - console.log('allManagingTeams:', allManagingTeams); + toast.info('allManagingTeams:', allManagingTeams); const uniqueMembers = uniqBy(allMembers, '_id'); uniqueMembers.forEach(member => { - const fromDate = moment().startOf('week').subtract(0, 'weeks'); - const toDate = moment().endOf('week').subtract(0, 'weeks'); + const fromDate = moment() + .startOf('week') + .subtract(0, 'weeks'); + const toDate = moment() + .endOf('week') + .subtract(0, 'weeks'); memberTimeEntriesPromises.push( - httpService.get(ENDPOINTS.TIME_ENTRIES_PERIOD(member._id, fromDate, toDate)).catch(err => {}) + httpService + .get(ENDPOINTS.TIME_ENTRIES_PERIOD(member._id, fromDate, toDate)) + .catch(() => { }), ); }); const memberTimeEntriesResponses = await Promise.all(memberTimeEntriesPromises); - for (let i = 0; i < uniqueMembers.length; i++) { + for (let i = 0; i < uniqueMembers.length; i += 1) { uniqueMembers[i] = { ...uniqueMembers[i], timeEntries: memberTimeEntriesResponses[i]?.data || [], }; } - for (let i = 0; i < allManagingTeams.length; i++) { - for (let j = 0; j < allManagingTeams[i].members.length; j++) { + for (let i = 0; i < allManagingTeams.length; i += 1) { + for (let j = 0; j < allManagingTeams[i].members.length; j += 1) { const memberDataWithTimeEntries = uniqueMembers.find( - member => member._id === allManagingTeams[i].members[j]._id + member => member._id === allManagingTeams[i].members[j]._id, ); allManagingTeams[i].members[j] = memberDataWithTimeEntries; } @@ -79,25 +106,11 @@ export const fetchAllManagingTeams = (userId, managingTeams) => async dispatch = await dispatch(setTeamsStart()); dispatch(setTeams(allManagingTeams)); } catch (err) { - console.error(err); + toast.error(err); dispatch(setTeamsError(err)); } }; -const setTeamsStart = () => ({ - type: FETCH_TEAMS_START, -}); - -const setTeams = payload => ({ - type: RECEIVE_TEAMS, - payload, -}); - -const setTeamsError = payload => ({ - type: FETCH_TEAMS_ERROR, - payload, -}); - export const getTeamDetail = teamId => { const url = ENDPOINTS.TEAM_BY_ID(teamId); return async dispatch => { @@ -113,8 +126,3 @@ export const getTeamDetail = teamId => { } }; }; - -export const setTeamDetail = data => ({ - type: GET_TEAM_BY_ID, - payload: data, -}); diff --git a/src/actions/teamCodes.js b/src/actions/teamCodes.js index 6ce12f96a6..a60c8b61e4 100644 --- a/src/actions/teamCodes.js +++ b/src/actions/teamCodes.js @@ -1,6 +1,6 @@ export const SET_TEAM_CODES = 'SET_TEAM_CODES'; export const setTeamCodes = teamCodes => ({ - type: SET_TEAM_CODES, - payload: teamCodes, + type: SET_TEAM_CODES, + payload: teamCodes, }); diff --git a/src/actions/timeEntries.js b/src/actions/timeEntries.js index 5eb2c35afd..259f68c3eb 100644 --- a/src/actions/timeEntries.js +++ b/src/actions/timeEntries.js @@ -1,8 +1,22 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable no-param-reassign */ import axios from 'axios'; +import { toast } from 'react-toastify'; import moment from 'moment'; import { GET_TIME_ENTRIES_WEEK, GET_TIME_ENTRIES_PERIOD } from '../constants/timeEntries'; import { ENDPOINTS } from '../utils/URL'; +export const setTimeEntriesForWeek = (data, offset) => ({ + type: GET_TIME_ENTRIES_WEEK, + payload: data, + offset, +}); + +export const setTimeEntriesForPeriod = data => ({ + type: GET_TIME_ENTRIES_PERIOD, + payload: data, +}); + /** * number === 0 current week * number === 1 last week @@ -43,6 +57,23 @@ export const getTimeEntriesForWeek = (userId, offset) => { }; }; +const updateTimeEntries = (timeEntry, oldDateOfWork) => { + const startOfWeek = moment().startOf('week'); + + return async dispatch => { + if (oldDateOfWork) { + const oldOffset = Math.ceil(startOfWeek.diff(oldDateOfWork, 'week', true)); + dispatch(getTimeEntriesForWeek(timeEntry.personId, oldOffset)); + } + + const offset = Math.ceil(startOfWeek.diff(timeEntry.dateOfWork, 'week', true)); + + if (offset <= 2 && offset >= 0) { + dispatch(getTimeEntriesForWeek(timeEntry.personId, offset)); + } + }; +}; + export const getTimeEntriesForPeriod = (userId, fromDate, toDate) => { toDate = moment(toDate) .endOf('day') @@ -71,19 +102,20 @@ export const getTimeEntriesForPeriod = (userId, fromDate, toDate) => { }; }; -export const getTimeEndDateEntriesByPeriod = (userId, fromDate, toDate) => { //Find last week of work in date +export const getTimeEndDateEntriesByPeriod = (userId, fromDate, toDate) => { + // Find last week of work in date toDate = moment(toDate) .endOf('day') .format('YYYY-MM-DDTHH:mm:ss'); - + const url = ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, toDate); - return async dispatch => { + return async () => { let loggedOut = false; try { const res = await axios.get(url); if (!res || !res.data) { - console.log("Request failed or no data"); - return "N/A"; + toast.info('Request failed or no data'); + return 'N/A'; } const filteredEntries = res.data.filter(entry => { const entryDate = moment(entry.dateOfWork); @@ -94,33 +126,34 @@ export const getTimeEndDateEntriesByPeriod = (userId, fromDate, toDate) => { //F }); const lastEntry = filteredEntries[0]; if (!lastEntry) { - return "N/A"; + return 'N/A'; } const lastEntryDate = lastEntry.createdDateTime; return lastEntryDate; } catch (error) { - console.error("Error fetching time entries:", error); + toast.error('Error fetching time entries:', error); if (error.response && error.response.status === 401) { loggedOut = true; } - return "N/A"; // Return "N/A" in case of error + return 'N/A'; // Return "N/A" in case of error } }; }; -export const getTimeStartDateEntriesByPeriod = (userId, fromDate, toDate) => { // Find first week of work in date +export const getTimeStartDateEntriesByPeriod = (userId, fromDate, toDate) => { + // Find first week of work in date toDate = moment(toDate) .endOf('day') .format('YYYY-MM-DDTHH:mm:ss'); - + const url = ENDPOINTS.TIME_ENTRIES_PERIOD(userId, fromDate, toDate); return async dispatch => { let loggedOut = false; try { const res = await axios.get(url); if (!res || !res.data) { - console.log("Request failed or no data"); - return "N/A"; + toast.info('Request failed or no data'); + return 'N/A'; } const filteredEntries = res.data.filter(entry => { const entryDate = moment(entry.dateOfWork); @@ -131,16 +164,16 @@ export const getTimeStartDateEntriesByPeriod = (userId, fromDate, toDate) => { / }); const firstEntry = filteredEntries[0]; if (!firstEntry) { - return "N/A"; + return 'N/A'; } const firstEntryDate = firstEntry.dateOfWork; return firstEntryDate; } catch (error) { - console.error("Error fetching time entries:", error); + toast.error('Error fetching time entries:', error); if (error.response && error.response.status === 401) { loggedOut = true; } - return "N/A"; // Return "N/A" in case of error + return 'N/A'; // Return "N/A" in case of error } }; }; @@ -149,7 +182,7 @@ export const postTimeEntry = timeEntry => { return async dispatch => { try { const res = await axios.post(url, timeEntry); - if (timeEntry.entryType == 'default') { + if (timeEntry.entryType === 'default') { dispatch(updateTimeEntries(timeEntry)); } return res.status; @@ -164,7 +197,7 @@ export const editTimeEntry = (timeEntryId, timeEntry, oldDateOfWork) => { return async dispatch => { try { const res = await axios.put(url, timeEntry); - if (timeEntry.entryType == 'default') { + if (timeEntry.entryType === 'default') { dispatch(updateTimeEntries(timeEntry, oldDateOfWork)); } return res.status; @@ -188,31 +221,3 @@ export const deleteTimeEntry = timeEntry => { } }; }; - -const updateTimeEntries = (timeEntry, oldDateOfWork) => { - const startOfWeek = moment().startOf('week'); - - return async dispatch => { - if (oldDateOfWork) { - const oldOffset = Math.ceil(startOfWeek.diff(oldDateOfWork, 'week', true)); - dispatch(getTimeEntriesForWeek(timeEntry.personId, oldOffset)); - } - - const offset = Math.ceil(startOfWeek.diff(timeEntry.dateOfWork, 'week', true)); - - if (offset <= 2 && offset >= 0) { - dispatch(getTimeEntriesForWeek(timeEntry.personId, offset)); - } - }; -}; - -export const setTimeEntriesForWeek = (data, offset) => ({ - type: GET_TIME_ENTRIES_WEEK, - payload: data, - offset, -}); - -export const setTimeEntriesForPeriod = data => ({ - type: GET_TIME_ENTRIES_PERIOD, - payload: data, -}); diff --git a/src/actions/timeOffRequestAction.js b/src/actions/timeOffRequestAction.js index c78d328d6a..c5f6391e15 100644 --- a/src/actions/timeOffRequestAction.js +++ b/src/actions/timeOffRequestAction.js @@ -1,4 +1,6 @@ +// eslint-disable-next-line import/no-unresolved import httpService from 'services/httpService'; +import { toast } from 'react-toastify'; import moment from 'moment'; import { FETCH_TIME_OFF_REQUESTS_SUCCESS, @@ -70,8 +72,13 @@ const isTimeOffRequestIncludeCurrentWeek = request => { const requestStartingDate = moment(startingDate); const requestEndingDate = moment(endingDate); - const currentWeekStart = moment().startOf('week').add(1, 'second'); - const currentWeekEnd = moment().endOf('week').subtract(1, 'day').subtract(1, 'second'); + const currentWeekStart = moment() + .startOf('week') + .add(1, 'second'); + const currentWeekEnd = moment() + .endOf('week') + .subtract(1, 'day') + .subtract(1, 'second'); // Check if the current week falls within the date range of the request if ( @@ -86,13 +93,7 @@ const isTimeOffRequestIncludeCurrentWeek = request => { const isUserOnVacation = requests => { moment.tz.setDefault('America/Los_Angeles'); - - for (const request of requests) { - if(isTimeOffRequestIncludeCurrentWeek(request)) { - return request; - } - } - return null; + return requests.find(request => isTimeOffRequestIncludeCurrentWeek(request)) || null; }; const isUserGoingOnVacation = requests => { @@ -111,7 +112,6 @@ const isUserGoingOnVacation = requests => { return userGoingOnVacation || null; }; - // Thunk Function export const getAllTimeOffRequests = () => async dispatch => { try { @@ -121,7 +121,7 @@ export const getAllTimeOffRequests = () => async dispatch => { const keys = Object.keys(requests); let onVacation = {}; let goingOnVacation = {}; - keys.forEach( key => { + keys.forEach(key => { const arrayOfRequests = requests[key]; const isUserOff = isUserOnVacation(arrayOfRequests); const isUserGoingOff = isUserGoingOnVacation(arrayOfRequests); @@ -130,7 +130,7 @@ export const getAllTimeOffRequests = () => async dispatch => { } else if (isUserGoingOff) { goingOnVacation = { ...goingOnVacation, [key]: { ...isUserGoingOff } }; } - }) + }); dispatch(addIsOnTimeOffRequests(onVacation)); dispatch(addGoingOnTimeOffRequests(goingOnVacation)); } catch (error) { @@ -144,7 +144,7 @@ export const addTimeOffRequestThunk = request => async dispatch => { const AddedRequest = response.data; dispatch(addTimeOffRequest(AddedRequest)); } catch (error) { - console.log(error); + toast.info(error); } }; @@ -155,7 +155,7 @@ export const updateTimeOffRequestThunk = (id, data) => async dispatch => { const updatedRequest = response.data; dispatch(updateTimeOffRequest(updatedRequest)); } catch (error) { - console.log(error); + toast.info(error); } }; @@ -165,6 +165,6 @@ export const deleteTimeOffRequestThunk = id => async dispatch => { const deletedRequest = response.data; dispatch(deleteTimeOffRequest(deletedRequest)); } catch (error) { - console.log(error); + toast.info(error); } }; diff --git a/src/actions/title.js b/src/actions/title.js index 5802ea1e2b..9385c8205b 100644 --- a/src/actions/title.js +++ b/src/actions/title.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { ENDPOINTS } from '../utils/URL'; export async function addTitle(titleData) { @@ -15,14 +16,13 @@ export async function addTitle(titleData) { } } - -export async function editTitle(titleData){ +export async function editTitle(titleData) { try { const url = ENDPOINTS.EDIT_OLD_TITLE(); const response = await axios.post(url, titleData); return Promise.resolve(response); } catch (error) { - console.log(error) + toast.info(error); return { message: error.response.data.message, errorCode: error.response.data.message, @@ -50,7 +50,7 @@ export async function getTitleById(titleId) { const url = ENDPOINTS.TITLE_BY_ID(titleId); const response = await axios.get(url); return Promise.resolve(response); - } catch { + } catch (error) { return { message: error.response.data.message, errorCode: error.response.data.message, @@ -64,7 +64,7 @@ export async function deleteTitleById(titleId) { const url = ENDPOINTS.DELETE_TITLE_BY_ID(titleId); const response = await axios.put(url); return Promise.resolve(response); - } catch { + } catch (error) { return { message: error.response.data.message, errorCode: error.response.data.message, diff --git a/src/actions/totalOrgSummary.js b/src/actions/totalOrgSummary.js index 2053c0dff6..e635429c60 100644 --- a/src/actions/totalOrgSummary.js +++ b/src/actions/totalOrgSummary.js @@ -65,13 +65,18 @@ export const fetchTotalOrgSummaryDataError = fetchingError => ({ }); export const getTotalOrgSummary = (startDate, endDate, comparisonStartDate, comparisonEndDate) => { - const url = ENDPOINTS.TOTAL_ORG_SUMMARY(startDate, endDate, comparisonStartDate, comparisonEndDate); + const url = ENDPOINTS.TOTAL_ORG_SUMMARY( + startDate, + endDate, + comparisonStartDate, + comparisonEndDate, + ); return async dispatch => { dispatch(fetchTotalOrgSummaryReportBegin()); try { const response = await axios.get(url); dispatch(fetchTotalOrgSummaryDataSuccess(response.data)); - return {status: response.status, data: response.data}; + return { status: response.status, data: response.data }; } catch (error) { dispatch(fetchTotalOrgSummaryDataError(error)); return error.response.status; @@ -83,7 +88,7 @@ export const getTotalOrgSummary = (startDate, endDate, comparisonStartDate, comp * Action to set the 'loading' flag to true. */ export const fetchVolunteerRolesTeamStatsBegin = () => ({ - type: actions.FETCH_VOLUNTEER_ROLES_TEAM_STATS_BEGIN + type: actions.FETCH_VOLUNTEER_ROLES_TEAM_STATS_BEGIN, }); /** @@ -91,7 +96,7 @@ export const fetchVolunteerRolesTeamStatsBegin = () => ({ * * @param {object} volunteerRoleTeamStats An Object with the count of active members in the team. */ -export const fetchVolunteerRolesTeamStatsSuccess = (volunteerRoleTeamStats) => ({ +export const fetchVolunteerRolesTeamStatsSuccess = volunteerRoleTeamStats => ({ type: actions.FETCH_VOLUNTEER_ROLES_TEAM_STATS_SUCCESS, payload: { volunteerRoleTeamStats }, }); @@ -106,20 +111,19 @@ export const fetchVolunteerRolesTeamStatsError = error => ({ payload: { error }, }); -export const getTeamStatsActiveMembers = (endDate, activeMembersMinimum) =>{ - -const url = ENDPOINTS.VOLUNTEER_ROLES_TEAM_STATS(endDate, activeMembersMinimum); +export const getTeamStatsActiveMembers = (endDate, activeMembersMinimum) => { + const url = ENDPOINTS.VOLUNTEER_ROLES_TEAM_STATS(endDate, activeMembersMinimum); return async dispatch => { dispatch(fetchVolunteerRolesTeamStatsBegin()); try { const response = await axios.get(url); dispatch(fetchVolunteerRolesTeamStatsSuccess(response.data)); return { - data: response.data + data: response.data, }; } catch (error) { dispatch(fetchVolunteerRolesTeamStatsError(error)); return error.response.status; } }; -} +}; diff --git a/src/actions/userManagement.js b/src/actions/userManagement.js index 3f90342c94..033076e828 100644 --- a/src/actions/userManagement.js +++ b/src/actions/userManagement.js @@ -1,5 +1,6 @@ import axios from 'axios'; import moment from 'moment'; +import { toast } from 'react-toastify'; import { FETCH_USER_PROFILES_ERROR, FETCH_USER_PROFILES_START, @@ -13,12 +14,94 @@ import { DISABLE_USER_PROFILE_EDIT, CHANGE_USER_PROFILE_PAGE, START_USER_INFO_UPDATE, - FINISH_USER_INFO_UPDATE, - ERROR_USER_INFO_UPDATE, } from '../constants/userManagement'; import { ENDPOINTS } from '../utils/URL'; import { UserStatus } from '../utils/enums'; -import { getTimeEndDateEntriesByPeriod, getTimeStartDateEntriesByPeriod } from './timeEntries'; +import { getTimeEndDateEntriesByPeriod } from './timeEntries'; + +/** + * Set a flag that fetching user profiles + */ +export const userProfilesFetchStartAction = () => { + return { + type: FETCH_USER_PROFILES_START, + }; +}; + +/** + * set Projects in store + * @param payload : projects [] + */ +export const userProfilesFetchCompleteACtion = payload => { + return { + type: RECEIVE_ALL_USER_PROFILES, + payload, + }; +}; + +/** + * Error when setting the user profiles list + * @param payload : error status code + */ +export const userProfilesFetchErrorAction = payload => { + return { + type: FETCH_USER_PROFILES_ERROR, + payload, + }; +}; + +/** + * Action for Updating an user profile + * @param {*} user : the updated user + */ +export const userProfileUpdateAction = user => { + return { + type: USER_PROFILE_UPDATE, + user, + }; +}; + +/** + * Delete user profile action + * @param {*} user : the deleted user + */ +export const userProfileDeleteAction = user => { + return { + type: USER_PROFILE_DELETE, + user, + }; +}; + +/** + * Error when fetching the user profils basic info + * @param payload : error status code + */ +export const userProfilesBasicInfoFetchErrorAction = payload => { + return { + type: FETCH_USER_PROFILE_BASIC_INFO_ERROR, + payload, + }; +}; + +/** + * Set a flag that starts fetching user profile basic info + */ +export const userProfilesBasicInfoFetchStartAction = () => { + return { + type: FETCH_USER_PROFILE_BASIC_INFO, + }; +}; + +/** + * Fetching user profile basic info + * @param payload : projects [] + */ +export const userProfilesBasicInfoFetchCompleteACtion = payload => { + return { + type: RECEIVE_USER_PROFILE_BASIC_INFO, + payload, + }; +}; /** * fetching all user profiles @@ -32,7 +115,7 @@ export const getAllUserProfile = () => { dispatch(userProfilesFetchCompleteACtion(res.data)); return res.data; }) - .catch(err => { + .catch(() => { dispatch(userProfilesFetchErrorAction()); }); }; @@ -59,11 +142,11 @@ export const updateUserStatus = (user, status, reactivationDate) => { getTimeEndDateEntriesByPeriod(user._id, user.createdDate, userProfile.toDate), ); if (lastEnddate !== 'N/A') { - //if work exists, set EndDate to that week + // if work exists, set EndDate to that week patchData.endDate = moment(lastEnddate).format('YYYY-MM-DDTHH:mm:ss'); userProfile.endDate = moment(lastEnddate).format('YYYY-MM-DDTHH:mm:ss'); } else { - //No work exists, set end date to start date + // No work exists, set end date to start date patchData.endDate = moment(user.createdDate); userProfile.endDate = moment(user.createdDate); } @@ -79,7 +162,7 @@ export const updateUserStatus = (user, status, reactivationDate) => { // Ensure the dispatched action is final (optional if optimistic update is sufficient) dispatch(userProfileUpdateAction(userProfile)); } catch (error) { - console.error('Error updating user status:', error); + toast.error('Error updating user status:', error); // Rollback to previous state on error dispatch(userProfileUpdateAction(user)); @@ -96,12 +179,9 @@ export const updateRehireableStatus = (user, isRehireable) => { return async dispatch => { const userProfile = { ...user, isRehireable }; const requestData = { isRehireable }; - try { - await axios.patch(ENDPOINTS.UPDATE_REHIREABLE_STATUS(user._id), requestData); - dispatch(userProfileUpdateAction(userProfile)); - } catch (err) { - throw err; - } + + await axios.patch(ENDPOINTS.UPDATE_REHIREABLE_STATUS(user._id), requestData); + dispatch(userProfileUpdateAction(userProfile)); }; }; @@ -118,11 +198,11 @@ export const toggleVisibility = (user, isVisible) => { const toggleVisibilityPromise = axios.patch(ENDPOINTS.TOGGLE_VISIBILITY(user._id), requestData); return async dispatch => { toggleVisibilityPromise - .then(res => { + .then(() => { dispatch(userProfileUpdateAction(userProfile)); }) .catch(err => { - console.error('failed to toggle visibility: ', err); + toast.error('failed to toggle visibility: ', err); }); }; }; @@ -139,68 +219,15 @@ export const deleteUser = (user, option) => { }); return async dispatch => { deleteProfilePromise - .then(res => { + .then(() => { dispatch(userProfileDeleteAction(user)); }) - .catch(err => { + .catch(() => { dispatch(userProfileDeleteAction(user)); }); }; }; -/** - * Set a flag that fetching user profiles - */ -export const userProfilesFetchStartAction = () => { - return { - type: FETCH_USER_PROFILES_START, - }; -}; - -/** - * set Projects in store - * @param payload : projects [] - */ -export const userProfilesFetchCompleteACtion = payload => { - return { - type: RECEIVE_ALL_USER_PROFILES, - payload, - }; -}; - -/** - * Error when setting the user profiles list - * @param payload : error status code - */ -export const userProfilesFetchErrorAction = payload => { - return { - type: FETCH_USER_PROFILES_ERROR, - payload, - }; -}; - -/** - * Action for Updating an user profile - * @param {*} user : the updated user - */ -export const userProfileUpdateAction = user => { - return { - type: USER_PROFILE_UPDATE, - user, - }; -}; - -/** - * Delete user profile action - * @param {*} user : the deleted user - */ -export const userProfileDeleteAction = user => { - return { - type: USER_PROFILE_DELETE, - user, - }; -}; - /** * update the user final day status * @param {*} user - the user to be updated @@ -221,7 +248,7 @@ export const updateUserFinalDayStatus = (user, status, finalDayDate) => { const updateProfilePromise = axios.patch(ENDPOINTS.USER_PROFILE(user._id), patchData); return async dispatch => { - updateProfilePromise.then(res => { + updateProfilePromise.then(() => { dispatch(userProfileUpdateAction(userProfile)); }); }; @@ -233,7 +260,11 @@ export const updateUserFinalDayStatusIsSet = (user, status, finalDayDate, isSet) // Prepare patch data const patchData = { status, - endDate: finalDayDate ? moment(finalDayDate).add(1, 'days').format('YYYY-MM-DD') : undefined, + endDate: finalDayDate + ? moment(finalDayDate) + .add(1, 'days') + .format('YYYY-MM-DD') + : undefined, isSet, }; @@ -248,7 +279,7 @@ export const updateUserFinalDayStatusIsSet = (user, status, finalDayDate, isSet) dispatch(userProfileUpdateAction(updatedUserProfile)); } catch (error) { - console.error('Error updating user profile:', error); + toast.error('Error updating user profile:', error); throw new Error('Failed to update user profile.'); } }; @@ -271,57 +302,26 @@ export const getUserProfileBasicInfo = () => { dispatch(userProfilesBasicInfoFetchCompleteACtion(res.data)); return res.data; // Return the fetched data }) - .catch(err => { + .catch(() => { // Dispatch error action if the fetch fails dispatch(userProfilesBasicInfoFetchErrorAction()); }); }; }; -/** - * Set a flag that starts fetching user profile basic info - */ -export const userProfilesBasicInfoFetchStartAction = () => { - return { - type: FETCH_USER_PROFILE_BASIC_INFO, - }; -}; - -/** - * Fetching user profile basic info - * @param payload : projects [] - */ -export const userProfilesBasicInfoFetchCompleteACtion = payload => { - return { - type: RECEIVE_USER_PROFILE_BASIC_INFO, - payload, - }; -}; - -/** - * Error when fetching the user profils basic info - * @param payload : error status code - */ -export const userProfilesBasicInfoFetchErrorAction = payload => { - return { - type: FETCH_USER_PROFILE_BASIC_INFO_ERROR, - payload, - }; -}; - -export const enableEditUserInfo = value => (dispatch, getState) => { +export const enableEditUserInfo = value => dispatch => { dispatch({ type: ENABLE_USER_PROFILE_EDIT, payload: value }); }; -export const disableEditUserInfo = value => (dispatch, getState) => { +export const disableEditUserInfo = value => dispatch => { dispatch({ type: DISABLE_USER_PROFILE_EDIT, payload: value }); }; -export const changePagination = value => (dispatch, getState) => { +export const changePagination = value => dispatch => { dispatch({ type: CHANGE_USER_PROFILE_PAGE, payload: value }); }; -export const updateUserInfomation = value => (dispatch, getState) => { +export const updateUserInfomation = value => dispatch => { dispatch({ type: START_USER_INFO_UPDATE, payload: value }); }; diff --git a/src/actions/userProfile.js b/src/actions/userProfile.js index bcb2bfbcac..84b1ae9d1e 100644 --- a/src/actions/userProfile.js +++ b/src/actions/userProfile.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import { GET_USER_PROFILE, GET_USER_TASKS, @@ -7,10 +8,45 @@ import { CLEAR_USER_PROFILE, GET_PROJECT_BY_USER_NAME, USER_NOT_FOUND_ERROR, - GET_USER_AUTOCOMPLETE + GET_USER_AUTOCOMPLETE, } from '../constants/userProfile'; import { ENDPOINTS } from '../utils/URL'; -import { toast } from 'react-toastify'; + +export const getProjectsByPersonActionCreator = data => ({ + type: GET_PROJECT_BY_USER_NAME, + payload: data, +}); + +const userNotFoundError = error => ({ + type: USER_NOT_FOUND_ERROR, + payload: error, +}); + +export const getUserProfileActionCreator = data => ({ + type: GET_USER_PROFILE, + payload: data, +}); + +export const getUserTaskActionCreator = data => ({ + type: GET_USER_TASKS, + payload: data, +}); + +export const editFirstNameActionCreator = data => ({ + type: EDIT_FIRST_NAME, + payload: data, +}); + +export const putUserProfileActionCreator = data => ({ + type: EDIT_USER_PROFILE, + payload: data, +}); + +// Action creator for user autocomplete +export const getUserAutocompleteActionCreator = data => ({ + type: GET_USER_AUTOCOMPLETE, + payload: data, +}); export const getUserProfile = userId => { const url = ENDPOINTS.USER_PROFILE(userId); @@ -26,6 +62,7 @@ export const getUserProfile = userId => { const resp = dispatch(getUserProfileActionCreator(res.data)); return resp.payload; } + return null; }; }; @@ -37,10 +74,10 @@ export const getUserTasks = userId => { if (res.status === 200) { dispatch(getUserTaskActionCreator(res.data)); } else { - console.log(`Get user task request status is not 200, status message: ${res.statusText}`) + toast.info(`Get user task request status is not 200, status message: ${res.statusText}`); } } catch (error) { - console.log(error); + toast.error(error); } }; }; @@ -55,7 +92,7 @@ export const putUserProfile = data => dispatch => { export const clearUserProfile = () => ({ type: CLEAR_USER_PROFILE }); -export const updateUserProfile = (userProfile) => { +export const updateUserProfile = userProfile => { const url = ENDPOINTS.USER_PROFILE(userProfile._id); return async dispatch => { const res = await axios.put(url, userProfile); @@ -87,15 +124,16 @@ export const getProjectsByUsersName = searchName => { } catch (error) { dispatch(userNotFoundError(error.message)); dispatch(getProjectsByPersonActionCreator([])); - toast.error("Could not find user or project, please try again"); + toast.error('Could not find user or project, please try again'); + return []; } }; }; // Action to get user suggestions for autocomplete -export const getUserByAutocomplete = (searchText) => { +export const getUserByAutocomplete = searchText => { const url = ENDPOINTS.USER_AUTOCOMPLETE(searchText); - return async (dispatch) => { + return async dispatch => { try { const res = await axios.get(url); dispatch(getUserAutocompleteActionCreator(res.data)); // Dispatching the data to the store @@ -106,39 +144,3 @@ export const getUserByAutocomplete = (searchText) => { } }; }; - -export const getProjectsByPersonActionCreator = data => ({ - type: GET_PROJECT_BY_USER_NAME, - payload: data -}); - -const userNotFoundError = (error) =>({ - type: USER_NOT_FOUND_ERROR, - payload: error, -}); - -export const getUserProfileActionCreator = data => ({ - type: GET_USER_PROFILE, - payload: data, -}); - -export const getUserTaskActionCreator = data => ({ - type: GET_USER_TASKS, - payload: data, -}); - -export const editFirstNameActionCreator = data => ({ - type: EDIT_FIRST_NAME, - payload: data, -}); - -export const putUserProfileActionCreator = data => ({ - type: EDIT_USER_PROFILE, - payload: data, -}); - -// Action creator for user autocomplete -export const getUserAutocompleteActionCreator = (data) => ({ - type: GET_USER_AUTOCOMPLETE, - payload: data, -}); \ No newline at end of file diff --git a/src/actions/userProjects.js b/src/actions/userProjects.js index 1b13e640bd..a754e0f4aa 100644 --- a/src/actions/userProjects.js +++ b/src/actions/userProjects.js @@ -1,13 +1,19 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import types from '../constants/userProjects'; import { ENDPOINTS } from '../utils/URL'; +export const setUserProjects = data => ({ + type: types.GET_USER_PROJECTS, + payload: data, +}); + export const getUserProjects = userId => { const url = ENDPOINTS.USER_PROJECTS(userId); return async dispatch => { const res = await axios.get(url).catch(err => { if (err.status !== 401) { - console.log('err.message', err.message); + toast.info('err.message', err.message); } }); if (res) { @@ -15,9 +21,3 @@ export const getUserProjects = userId => { } }; }; - -export const setUserProjects = data => ({ - type: types.GET_USER_PROJECTS, - payload: data, -}); - diff --git a/src/actions/warnings.js b/src/actions/warnings.js index 6eea2b97e4..5f06cfb2c3 100644 --- a/src/actions/warnings.js +++ b/src/actions/warnings.js @@ -22,9 +22,8 @@ export const getWarningsByUserId = userId => { } catch (error) { if (error.response && error.response.status === 400) { return { error: error.response.data.message }; - } else { - return { error: error.message }; } + return { error: error.message }; } }; }; @@ -42,9 +41,8 @@ export const postWarningByUserId = warningData => { } catch (error) { if (error.response && error.response.status === 200) { return { error: error.message }; - } else { - return { error: error }; } + return { error }; } }; }; @@ -60,9 +58,8 @@ export const deleteWarningsById = (warningId, personId) => { } catch (error) { if (error.response && error.response.status === 400) { return { error: error.response.data.message }; - } else { - return { error: 'Something else went wrong' }; } + return { error: 'Something else went wrong' }; } }; }; @@ -80,9 +77,8 @@ export const getWarningDescriptions = () => { } catch (error) { if (error.response && error.response.status === 400) { return { error: error.response.data.message }; - } else { - return { error: error }; } + return { error }; } }; }; diff --git a/src/actions/wbs.js b/src/actions/wbs.js index 3d29eca10f..00bd72062f 100644 --- a/src/actions/wbs.js +++ b/src/actions/wbs.js @@ -3,9 +3,56 @@ * Author: Henry Ng - 03/20/20 ******************************************************************************* */ import axios from 'axios'; +import { toast } from 'react-toastify'; import * as types from '../constants/WBS'; import { ENDPOINTS } from '../utils/URL'; +/** + * Set a flag that fetching WBS + */ +export const setWBSStart = () => { + return { + type: types.FETCH_WBS_START, + }; +}; + +/** + * set WBS in store + * @param payload : WBS [] + */ +export const setWBS = WBSItems => { + return { + type: types.RECEIVE_WBS, + WBSItems, + }; +}; + +/** + * Error when setting project + * @param payload : error status code + */ +export const setWBSError = err => { + return { + type: types.FETCH_WBS_ERROR, + err, + }; +}; + +export const removeWBS = wbsId => { + return { + type: types.DELETE_WBS, + wbsId, + }; +}; + +export const postNewWBS = (wbs, status) => { + return { + type: types.ADD_NEW_WBS, + wbs, + status, + }; +}; + export const addNewWBS = (wbsName, projectId) => { const url = ENDPOINTS.WBS(projectId); return async dispatch => { @@ -19,7 +66,7 @@ export const addNewWBS = (wbsName, projectId) => { _id = res.data._id; status = res.status; } catch (err) { - console.log('TRY CATCH ERR', err); + toast.info('TRY CATCH ERR', err); status = 400; } @@ -44,6 +91,7 @@ export const deleteWbs = wbsId => { return response; } catch (err) { dispatch(setWBSError(err)); + return null; } }; }; @@ -62,49 +110,3 @@ export const fetchAllWBS = projectId => { }); }; }; - -/** - * Set a flag that fetching WBS - */ -export const setWBSStart = () => { - return { - type: types.FETCH_WBS_START, - }; -}; - -/** - * set WBS in store - * @param payload : WBS [] - */ -export const setWBS = WBSItems => { - return { - type: types.RECEIVE_WBS, - WBSItems, - }; -}; - -/** - * Error when setting project - * @param payload : error status code - */ -export const setWBSError = err => { - return { - type: types.FETCH_WBS_ERROR, - err, - }; -}; - -export const removeWBS = wbsId => { - return { - type: types.DELETE_WBS, - wbsId, - }; -}; - -export const postNewWBS = (wbs, status) => { - return { - type: types.ADD_NEW_WBS, - wbs, - status, - }; -}; diff --git a/src/actions/weeklySummaries.js b/src/actions/weeklySummaries.js index aabadbadc1..b53b9febdb 100644 --- a/src/actions/weeklySummaries.js +++ b/src/actions/weeklySummaries.js @@ -1,9 +1,7 @@ import axios from 'axios'; import * as actions from '../constants/weeklySummaries'; import { ENDPOINTS } from '../utils/URL'; -import { - getUserProfileActionCreator, -} from '../actions/userProfile'; +import { getUserProfileActionCreator } from './userProfile'; /** * Action to set the 'loading' flag to true. @@ -43,21 +41,26 @@ export const getWeeklySummaries = userId => { dispatch(fetchWeeklySummariesBegin()); try { const response = await axios.get(url); - // Only pick the fields related to weekly summaries from the userProfile. const { weeklySummariesCount, weeklySummaries, mediaUrl, adminLinks } = response.data; - let summaryDocLink; - for (const link in adminLinks) { - if (adminLinks[link].Name === 'Media Folder') { - summaryDocLink = adminLinks[link].Link; - break; - } - } - dispatch(fetchWeeklySummariesSuccess({ weeklySummariesCount, weeklySummaries, mediaUrl:summaryDocLink || mediaUrl})); + + const foundMediaFolderLink = Array.isArray(adminLinks) + ? adminLinks.find(link => link.Name === 'Media Folder') + : null; + + const summaryDocLink = foundMediaFolderLink?.Link; + + dispatch( + fetchWeeklySummariesSuccess({ + weeklySummariesCount, + weeklySummaries, + mediaUrl: summaryDocLink || mediaUrl, + }), + ); dispatch(getUserProfileActionCreator(response.data)); return response.status; } catch (error) { dispatch(fetchWeeklySummariesError(error)); - return error.response.status; + return error.response?.status || 500; } }; }; @@ -70,47 +73,42 @@ export const getWeeklySummaries = userId => { */ export const updateWeeklySummaries = (userId, weeklySummariesData) => { const url = ENDPOINTS.USER_PROFILE(userId); - return async (dispatch) => { + return async dispatch => { try { - // Get the user's profile from the server. let response = await axios.get(url); - const userProfile = await response.data; + const userProfile = response.data; const adminLinks = userProfile.adminLinks || []; - // Merge the weekly summaries related changes with the user's profile. - const {mediaUrl, weeklySummaries, weeklySummariesCount } = weeklySummariesData; - - // update the changes on weekly summaries link into admin links + const { mediaUrl, weeklySummaries, weeklySummariesCount } = weeklySummariesData; + let doesMediaFolderExist = false; - for (const link of adminLinks) { + const updatedAdminLinks = adminLinks.map(link => { if (link.Name === 'Media Folder') { - link.Link = mediaUrl; doesMediaFolderExist = true; - break; + return { ...link, Link: mediaUrl }; } + return link; + }); + + if (!doesMediaFolderExist && mediaUrl) { + updatedAdminLinks.push({ Name: 'Media Folder', Link: mediaUrl }); } - if(!doesMediaFolderExist && mediaUrl){ - adminLinks.push( - {Name:'Media Folder',Link:mediaUrl} - ) - } + const userProfileUpdated = { ...userProfile, - adminLinks, + adminLinks: updatedAdminLinks, mediaUrl, weeklySummaries, weeklySummariesCount, }; - - // Update the user's profile on the server. response = await axios.put(url, userProfileUpdated); if (response.status === 200) { await dispatch(getUserProfileActionCreator(userProfileUpdated)); } return response.status; } catch (error) { - return error.response.status; + return error.response?.status || 500; } }; }; diff --git a/src/actions/weeklySummariesAIPrompt.js b/src/actions/weeklySummariesAIPrompt.js index 08c023ecef..1a8f71aadb 100644 --- a/src/actions/weeklySummariesAIPrompt.js +++ b/src/actions/weeklySummariesAIPrompt.js @@ -1,23 +1,21 @@ -import { ENDPOINTS } from '../utils/URL'; import axios from 'axios'; +import { ENDPOINTS } from '../utils/URL'; import { - getAIPrompt as getAIPrompt, - updateAIPrompt as updateAIPrompt, - updateCopiedPrompt as updateCopiedPrompt, - getCopiedPromptDate as getCopiedPromptDate, + getAIPrompt, + updateAIPrompt, + updateCopiedPrompt, + getCopiedPromptDate, } from '../constants/weeklySummariesAIPrompt'; export const getDashboardDataAI = () => { const DashboardDataAIPromise = axios.get(ENDPOINTS.AI_PROMPT()); return async dispatch => { - return DashboardDataAIPromise - .then((res) => { - dispatch(getAIPrompt(res.data)); - return res.data; - }) - .catch(() => { - dispatch(getAIPrompt(undefined)); - }); + return DashboardDataAIPromise.then(res => { + dispatch(getAIPrompt(res.data)); + return res.data; + }).catch(() => { + dispatch(getAIPrompt(undefined)); + }); }; }; @@ -26,32 +24,26 @@ export const updateDashboardData = textPrompt => { aIPromptText: textPrompt, }; return async dispatch => { - await axios - .put(ENDPOINTS.AI_PROMPT(), updatedData) - .then(dispatch(updateAIPrompt(textPrompt))); + await axios.put(ENDPOINTS.AI_PROMPT(), updatedData).then(dispatch(updateAIPrompt(textPrompt))); }; }; // =========================================================================== // This function is executed each time the user copies the AI prompt from the modal and updates the copied Date in the userProfile - Sucheta -export const updateCopiedPromptDate = (userId) => { +export const updateCopiedPromptDate = userId => { return async dispatch => { - await axios.put(ENDPOINTS.COPIED_AI_PROMPT(userId)) - .then(dispatch(updateCopiedPrompt(userId))); - } - } + await axios.put(ENDPOINTS.COPIED_AI_PROMPT(userId)).then(dispatch(updateCopiedPrompt(userId))); + }; +}; // This function is executed each time there is change of copied AI prompt date - Sucheta -export const getCopiedDateOfPrompt = (userId) =>{ +export const getCopiedDateOfPrompt = userId => { const CopiedPromptDate = axios.get(ENDPOINTS.COPIED_AI_PROMPT(userId)); - return async dispatch =>{ - return CopiedPromptDate - .then(res=>{ + return async dispatch => { + return CopiedPromptDate.then(res => { dispatch(getCopiedPromptDate(res.data.message)); return res.data.message; - }) - .catch(()=>{ + }).catch(() => { dispatch(getCopiedPromptDate(undefined)); - }) - } - -} \ No newline at end of file + }); + }; +}; diff --git a/src/actions/weeklySummariesReport.js b/src/actions/weeklySummariesReport.js index 4365a1da7b..ccc15ea3b9 100644 --- a/src/actions/weeklySummariesReport.js +++ b/src/actions/weeklySummariesReport.js @@ -1,7 +1,7 @@ import axios from 'axios'; +import { toast } from 'react-toastify'; import * as actions from '../constants/weeklySummariesReport'; import { ENDPOINTS } from '../utils/URL'; -import { toast } from 'react-toastify'; /** * Action to set the 'loading' flag to true. @@ -51,7 +51,7 @@ export const getWeeklySummariesReport = () => { try { const response = await axios.get(url); dispatch(fetchWeeklySummariesReportSuccess(response.data)); - return {status: response.status, data: response.data}; + return { status: response.status, data: response.data }; } catch (error) { dispatch(fetchWeeklySummariesReportError(error)); return error.response.status; @@ -62,22 +62,19 @@ export const getWeeklySummariesReport = () => { export const updateOneSummaryReport = (userId, updatedField) => { const url = ENDPOINTS.USER_PROFILE(userId); return async dispatch => { - try { - const { data: userProfile } = await axios.get(url); - const res = await axios.put(url, { - ...userProfile, - ...updatedField, - }); - if (res.status === 200) { - dispatch(updateSummaryReport({ _id: userId, updatedField })); - return res; - } else { - throw new Error(`An error occurred while attempting to save the changes to the profile.`) - } - } catch (err) { - throw err; + const { data: userProfile } = await axios.get(url); + const res = await axios.put(url, { + ...userProfile, + ...updatedField, + }); + + if (res.status === 200) { + dispatch(updateSummaryReport({ _id: userId, updatedField })); + return res; } - } + + throw new Error(`An error occurred while attempting to save the changes to the profile.`); + }; }; /** @@ -100,8 +97,8 @@ export const toggleUserBio = (userId, bioPosted) => { return res; } catch (error) { - toast.error("An error occurred while updating bio status."); + toast.error('An error occurred while updating bio status.'); throw error; } }; -}; \ No newline at end of file +}; diff --git a/src/actions/weeklySummariesReportRecepients.js b/src/actions/weeklySummariesReportRecepients.js index 4d9d4b754d..46cb97d476 100644 --- a/src/actions/weeklySummariesReportRecepients.js +++ b/src/actions/weeklySummariesReportRecepients.js @@ -1,33 +1,34 @@ +import axios from 'axios'; +import { toast } from 'react-toastify'; import * as actions from '../constants/weeklySummariesReport'; import { ENDPOINTS } from '../utils/URL'; -import axios from 'axios'; -export const authorizeWeeklySummaries = (message) => ({ +export const authorizeWeeklySummaries = message => ({ type: actions.AUTHORIZE_WEEKLY_SUMMARY_REPORTS, - payload: message -}) + payload: message, +}); -export const authorizeWeeklySummariesReportError = (errorMsg) => ({ +export const authorizeWeeklySummariesReportError = errorMsg => ({ type: actions.AUTHORIZE_WEEKLYSUMMARIES_REPORTS_ERROR, - payload: errorMsg -}) + payload: errorMsg, +}); // export const saveWeeklySummary = (message) => ({ // type: actions.SAVE_WEEKLY_SUMMARIES_RECIPIENTS, // payload: message // }) -export const getRecepients = (recepientsArr) => ({ +export const getRecepients = recepientsArr => ({ type: actions.GET_SUMMARY_RECIPIENTS, - recepientsArr -}) + recepientsArr, +}); -export const getRecepientsError = (err) => ({ +export const getRecepientsError = err => ({ type: actions.GET_SUMMARY_RECIPIENTS_ERROR, - payload: err -}) + payload: err, +}); -export const addSummaryRecipient = (userid) => { +export const addSummaryRecipient = userid => { const url = ENDPOINTS.SAVE_SUMMARY_RECEPIENTS(userid); return async dispatch => { try { @@ -35,19 +36,19 @@ export const addSummaryRecipient = (userid) => { // dispatch(saveWeeklySummary(response.data.message)); return response.status; } catch (error) { - console.log("response for Error:", error) + toast.info('response for Error:', error); dispatch(authorizeWeeklySummariesReportError(error)); - // return error.response.status; + return error; } }; -} +}; -export const deleteRecipient = (userid) => ({ +export const deleteRecipient = userid => ({ type: actions.DELETE_WEEKLY_SUMMARIES_RECIPIENTS, - payload: {userid} -}) + payload: { userid }, +}); -export const deleteSummaryRecipient = (userid) => { +export const deleteSummaryRecipient = userid => { const url = ENDPOINTS.SAVE_SUMMARY_RECEPIENTS(userid); return async dispatch => { try { @@ -55,12 +56,12 @@ export const deleteSummaryRecipient = (userid) => { dispatch(deleteRecipient(userid)); return response.status; } catch (error) { - console.log("response for Error:", error) + toast.info('response for Error:', error); dispatch(authorizeWeeklySummariesReportError(error)); - // return error.response.status; + return error; } }; -} +}; export const getSummaryRecipients = () => { const url = ENDPOINTS.GET_SUMMARY_RECEPIENTS(); @@ -70,9 +71,9 @@ export const getSummaryRecipients = () => { dispatch(getRecepients(response.data)); return response.data; } catch (error) { - console.log("response for Error:", error) + toast.info('response for Error:', error); dispatch(getRecepientsError(error)); - // return error.response.status; + return error; } }; -} +}; diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index 7d053a5394..d80719396b 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -15,6 +15,8 @@ import { DEV_ADMIN_ACCOUNT_CUSTOM_WARNING_MESSAGE_DEV_ENV_ONLY, PROTECTED_ACCOUNT_MODIFICATION_WARNING_MESSAGE, } from 'utils/constants'; +import { useDispatch } from 'react-redux'; +import { updateSummaryBarData } from 'actions/dashboardActions'; export function Dashboard(props) { const [popup, setPopup] = useState(false); @@ -27,6 +29,8 @@ export function Dashboard(props) { const isNotAllowedToEdit = cantUpdateDevAdminDetails(viewingUser?.email, authUser.email); const darkMode = useSelector(state => state.theme.darkMode); + const dispatch = useDispatch(); + const toggle = (forceOpen = null) => { if (isNotAllowedToEdit) { const warningMessage = @@ -61,6 +65,11 @@ export function Dashboard(props) { }; }, []); + useEffect(()=>{ + console.log(summaryBarData) + dispatch(updateSummaryBarData({summaryBarData})); + },[summaryBarData]) + return ( { +function ConfirmationMessage({ message, isSuccess, confirmationMessageCallback }) { const history = useHistory(); return (
- {isSuccess &&
} -

+ {isSuccess &&
} +

{isSuccess && (

@@ -22,17 +21,10 @@ const ConfirmationMessage = ({ message, isSuccess, confirmationMessageCallback }
)} - {!isSuccess ? ( -

- {' '} -

- {message} -

- ) : ( -

- )} + {!isSuccess &&

{message}

}
); -}; +} export default ConfirmationMessage; diff --git a/src/components/EmailSubscribeForm/Unsubscribe/ConfirmationMessage.js b/src/components/EmailSubscribeForm/Unsubscribe/ConfirmationMessage.js index 8d1cb67735..06a155d727 100644 --- a/src/components/EmailSubscribeForm/Unsubscribe/ConfirmationMessage.js +++ b/src/components/EmailSubscribeForm/Unsubscribe/ConfirmationMessage.js @@ -1,23 +1,26 @@ +// eslint-disable-next-line no-unused-vars import React from 'react'; -import styles from './ConfirmationMessage.module.css'; // Make sure to create this CSS module import { useHistory } from 'react-router-dom'; +import styles from './ConfirmationMessage.module.css'; // Make sure to create this CSS module -const ConfirmationMessage = ({ message, isSuccess, confirmationMessageCallback }) => { +// function ConfirmationMessage({ message, isSuccess, confirmationMessageCallback }) { +function ConfirmationMessage({ isSuccess, confirmationMessageCallback }) { const history = useHistory(); return (
- {isSuccess &&
} -

-

+ {isSuccess &&
} +

+

-

+

); -}; +} export default ConfirmationMessage; diff --git a/src/components/EmailSubscribeForm/Unsubscribe/index.js b/src/components/EmailSubscribeForm/Unsubscribe/index.js index 5ffb01c2e4..8d1ca219d2 100644 --- a/src/components/EmailSubscribeForm/Unsubscribe/index.js +++ b/src/components/EmailSubscribeForm/Unsubscribe/index.js @@ -1,15 +1,16 @@ +// eslint-disable-next-line no-unused-vars import React, { useState, useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; +// import { set } from 'lodash'; import styles from './SubscribePage.module.css'; // Import the CSS module import { removeNonHgnUserEmailSubscription, addNonHgnUserEmailSubscription, } from '../../../actions/sendEmails'; -import { useLocation } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; import ConfirmationMessage from './ConfirmationMessage'; -import { set } from 'lodash'; -const SubscribePage = () => { +function SubscribePage() { const dispatch = useDispatch(); const query = new URLSearchParams(useLocation().search); const [email, setEmail] = useState(''); @@ -17,8 +18,8 @@ const SubscribePage = () => { const [confirmationMessage, setConfirmationMessage] = useState(''); const [confirmationStatus, setConfirmationStatus] = useState(false); useEffect(() => { - const email = query.get('email'); - if (email) { + const queryemail = query.get('email'); + if (queryemail) { removeNonHgnUserEmailSubscription(email).then(result => { if (result.success) { // Handle success @@ -33,8 +34,8 @@ const SubscribePage = () => { } }, [query]); - const validateEmail = email => { - return /\S+@\S+\.\S+/.test(email); + const validateEmail = emailval => { + return /\S+@\S+\.\S+/.test(emailval); }; const confirmationMessageCallback = () => { @@ -45,7 +46,7 @@ const SubscribePage = () => { event.preventDefault(); if (validateEmail(email)) { dispatch(addNonHgnUserEmailSubscription(email)); - console.log('Email valid, submit to the server:', email); + // console.log('Email valid, submit to the server:', email); setEmail(''); setError(''); } else { @@ -55,13 +56,11 @@ const SubscribePage = () => { if (confirmationMessage) { return ( - <> - - + ); } @@ -70,9 +69,9 @@ const SubscribePage = () => {

Subscribe for Weekly Updates

{/* ... */}

- Join our mailing list for updates. We'll send a confirmation to ensure you're the owner of - the email provided. Once confirmed, we promise only a single email per week. Don't forget to - check your spam folder if you didn't receive the confirmation! + Join our mailing list for updates. We'll send a confirmation to ensure you're the + owner of the email provided. Once confirmed, we promise only a single email per week. + Don't forget to check your spam folder if you didn't receive the confirmation!

Want to opt out later? No problem, every email has an unsubscribe link at the bottom. @@ -92,6 +91,6 @@ const SubscribePage = () => { {/* ... */}

); -}; +} export default SubscribePage; diff --git a/src/components/EmailSubscribeForm/UnsubscribeForm.js b/src/components/EmailSubscribeForm/UnsubscribeForm.js index a74d69552d..b1d3860c6c 100644 --- a/src/components/EmailSubscribeForm/UnsubscribeForm.js +++ b/src/components/EmailSubscribeForm/UnsubscribeForm.js @@ -1,15 +1,14 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; import styles from './SubscribePage.module.css'; // Import the CSS module import { addNonHgnUserEmailSubscription, confirmNonHgnUserEmailSubscription, } from '../../actions/sendEmails'; -import { useLocation } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; import ConfirmationMessage from './ConfirmationMessage'; -import { set } from 'lodash'; -const UnsubscribeForm = () => { +function UnsubscribeForm() { const dispatch = useDispatch(); const query = new URLSearchParams(useLocation().search); const [email, setEmail] = useState(''); @@ -33,8 +32,8 @@ const UnsubscribeForm = () => { } }, [query]); - const validateEmail = email => { - return /\S+@\S+\.\S+/.test(email); + const validateEmail = emailVal => { + return /\S+@\S+\.\S+/.test(emailVal); }; const confirmationMessageCallback = () => { @@ -45,7 +44,7 @@ const UnsubscribeForm = () => { event.preventDefault(); if (validateEmail(email)) { dispatch(addNonHgnUserEmailSubscription(email)); - console.log('Email valid, submit to the server:', email); + // console.log('Email valid, submit to the server:', email); setEmail(''); setError(''); } else { @@ -55,13 +54,11 @@ const UnsubscribeForm = () => { if (confirmationMessage) { return ( - <> - - + ); } @@ -70,9 +67,9 @@ const UnsubscribeForm = () => {

Subscribe for Weekly Updates

{/* ... */}

- Join our mailing list for updates. We'll send a confirmation to ensure you're the owner of - the email provided. Once confirmed, we promise only a single email per week. Don't forget to - check your spam folder if you didn't receive the confirmation! + Join our mailing list for updates. We&apo;ll send a confirmation to ensure you&apo;re the + owner of the email provided. Once confirmed, we promise only a single email per week. + Don&apo;t forget to check your spam folder if you didn&apo;t receive the confirmation!

Want to opt out later? No problem, every email has an unsubscribe link at the bottom. @@ -92,6 +89,6 @@ const UnsubscribeForm = () => { {/* ... */}

); -}; +} export default UnsubscribeForm; diff --git a/src/components/EmailSubscribeForm/index.js b/src/components/EmailSubscribeForm/index.js index d385d6f342..3b775a5e24 100644 --- a/src/components/EmailSubscribeForm/index.js +++ b/src/components/EmailSubscribeForm/index.js @@ -1,15 +1,15 @@ +// eslint-disable-next-line no-unused-vars import React, { useState, useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; import styles from './SubscribePage.module.css'; // Import the CSS module import { addNonHgnUserEmailSubscription, confirmNonHgnUserEmailSubscription, } from '../../actions/sendEmails'; -import { useLocation } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; import ConfirmationMessage from './ConfirmationMessage'; -import { set } from 'lodash'; -const SubscribePage = () => { +function SubscribePage() { const dispatch = useDispatch(); const query = new URLSearchParams(useLocation().search); const [email, setEmail] = useState(''); @@ -33,8 +33,8 @@ const SubscribePage = () => { } }, [query]); - const validateEmail = email => { - return /\S+@\S+\.\S+/.test(email); + const validateEmail = emailval => { + return /\S+@\S+\.\S+/.test(emailval); }; const confirmationMessageCallback = () => { @@ -45,7 +45,7 @@ const SubscribePage = () => { event.preventDefault(); if (validateEmail(email)) { dispatch(addNonHgnUserEmailSubscription(email)); - console.log('Email valid, submit to the server:', email); + // console.log('Email valid, submit to the server:', email); setEmail(''); setError(''); } else { @@ -55,25 +55,23 @@ const SubscribePage = () => { if (confirmationMessage) { return ( - <> - - + ); } return (
-
+

Subscribe for Weekly Updates

{/* ... */}

- Join our mailing list for updates. We'll send a confirmation to ensure you're the owner of - the email provided. Once confirmed, we promise only a single email per week. Don't forget to - check your spam folder if you didn't receive the confirmation! + Join our mailing list for updates. We'll send a confirmation to ensure you're the + owner of the email provided. Once confirmed, we promise only a single email per week. + Don't forget to check your spam folder if you didn't receive the confirmation!

Want to opt out later? No problem, every email has an unsubscribe link at the bottom. @@ -93,6 +91,6 @@ const SubscribePage = () => { {/* ... */}

); -}; +} export default SubscribePage; diff --git a/src/components/Header/BellNotification.jsx b/src/components/Header/BellNotification.jsx index f3522c97a6..b8b19d04b5 100644 --- a/src/components/Header/BellNotification.jsx +++ b/src/components/Header/BellNotification.jsx @@ -2,7 +2,7 @@ import { useState, useEffect, useCallback, useRef, useMemo } from 'react'; import { useSelector } from 'react-redux'; -export default function BellNotification() { +export default function BellNotification({userId}) { // State variables to manage notifications and UI state const [hasNotification, setHasNotification] = useState(false); const [isDataReady, setIsDataReady] = useState(false); @@ -13,7 +13,13 @@ export default function BellNotification() { const timeEntries = useSelector(state => state.timeEntries?.weeks?.[0] || []); const weeklycommittedHours = useSelector(state => state.userProfile?.weeklycommittedHours || 0); const darkMode = useSelector(state => state.theme.darkMode); - const userId = useSelector(state => state.auth.user?.userid); + // const userId = useSelector(state => { + // console.log(state.auth) + // return state.auth.user?.userid}); + // const checkSessionStorage = () => JSON.parse(sessionStorage.getItem('viewingUser')) ?? false; + // const [viewingUser, setViewingUser] = useState(checkSessionStorage); + // const [displayUserId, setDisplayUserId] = useState( viewingUser?.userId || userId); + /** * Memoized function to calculate the total effort (hours + minutes) logged by the user @@ -127,6 +133,10 @@ export default function BellNotification() { }; }, []); + useEffect(() => { + setIsDataReady(false); + },[userId]) + /** * Utility function to format time values in hours and minutes */ diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index d7e85b169c..bd44da8d45 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -441,7 +441,7 @@ export function Header(props) { )} - + {(canAccessUserManagement || canAccessBadgeManagement || diff --git a/src/components/PermissionsManagement/PermissionsConst.js b/src/components/PermissionsManagement/PermissionsConst.js index 59b4bd76ae..56b8a4d974 100644 --- a/src/components/PermissionsManagement/PermissionsConst.js +++ b/src/components/PermissionsManagement/PermissionsConst.js @@ -158,6 +158,12 @@ export const permissionLabels = [ description: 'Gives the user permission to change the requirement to the user to submit a summary.', }, + { + label: 'Update Password (Others)', + key: 'updatePassword', + description: + 'Gives the user permission to update the password of any user but Owner/Admin classes. ', + }, { label: 'Manage Time Off Requests', key: 'manageTimeOffRequests', diff --git a/src/components/Reports/PeopleReport/PeopleReport.jsx b/src/components/Reports/PeopleReport/PeopleReport.jsx index f1fdce329a..dfc4b2dfa6 100644 --- a/src/components/Reports/PeopleReport/PeopleReport.jsx +++ b/src/components/Reports/PeopleReport/PeopleReport.jsx @@ -267,6 +267,16 @@ class PeopleReport extends Component { }); } + // eslint-disable-next-line class-methods-use-this + // endOfWeek(offset) { + // return moment() + // .tz('America/Los_Angeles') + // .endOf('week') + // .subtract(offset, 'weeks') + // .format('YYYY-MM-DD'); + // } + + render() { const { userProfile, @@ -278,10 +288,13 @@ class PeopleReport extends Component { toDate, timeEntries, } = this.state; - const { firstName, lastName, weeklycommittedHours } = userProfile; - const { tangibleHoursReportedThisWeek, auth, match, darkMode, totalTangibleHours } = this.props; + // eslint-disable-next-line no-unused-vars + const { firstName, lastName, weeklycommittedHours, hoursByCategory } = userProfile; + const { tangibleHoursReportedThisWeek, auth, match, darkMode } = this.props; - const totalTangibleHrsRound = totalTangibleHours.toFixed(2); + const totalTangibleHrsRound = (timeEntries.period?.reduce((total, entry) => { + return total + (entry.hours + (entry.minutes / 60)); + }, 0) || 0).toFixed(2); // eslint-disable-next-line react/no-unstable-nested-components,no-unused-vars function UserProject(props) { @@ -305,7 +318,7 @@ class PeopleReport extends Component { } } - const startdate = Object.keys(dict)[0]; + const [startdate] = Object.keys(dict); if (startdate) { startdate.toString(); } @@ -354,7 +367,7 @@ class PeopleReport extends Component { intentInfo: '', }; const resourcesName = []; - + if (userTask[i].isActive) { task.active = 'Yes'; } else { @@ -386,12 +399,17 @@ class PeopleReport extends Component { } task._id = userTask[i]._id; task.resources.push(resourcesName); - if (userTask[i].startedDatetime == null) { - task.startDate = 'null'; - } - if (userTask[i].endedDatime == null) { - task.endDate = 'null'; - } + // startedDatetime + // if (userTask[i].startedDatetime === null && userTask[i].startedDatetime !== "") { + // task.startDate = 'null'; + // } + // if (userTask[i].dueDatetime === null && userTask[i].dueDatetime !== "") { + // task.endDate = 'null'; + // } + // task.startDate = userTask[i].startedDatetime.split('T')[0]; + // task.endDate = userTask[i].dueDatetime.split('T')[0]; + task.startDate = userTask[i].startedDatetime ? userTask[i].startedDatetime.split('T')[0] : 'null'; + task.endDate = userTask[i].dueDatetime ? userTask[i].dueDatetime.split('T')[0] : 'null'; task.hoursBest = userTask[i].hoursBest; task.hoursMost = userTask[i].hoursMost; task.hoursWorst = userTask[i].hoursWorst; @@ -408,8 +426,7 @@ class PeopleReport extends Component { darkMode={darkMode} /> ); - } - + }; const renderProfileInfo = () => { const { isRehireable, bioStatus, authRole } = this.state; const { profilePic, role, jobTitle, endDate, _id, startDate } = userProfile; @@ -505,7 +522,7 @@ class PeopleReport extends Component { return (
-
+
-

{tangibleHoursReportedThisWeek}

+

{!Number.isNaN(tangibleHoursReportedThisWeek)?tangibleHoursReportedThisWeek:""}

Hours Logged This Week

)} @@ -554,12 +571,12 @@ class PeopleReport extends Component {
{this.state.isLoading ? ( -

Loading tasks:   -

+
) : activeTasks.length > 0 ? ( <>
diff --git a/src/components/Reports/PeopleReport/__tests__/selectors.test.js b/src/components/Reports/PeopleReport/__tests__/selectors.test.js deleted file mode 100644 index 03098265c1..0000000000 --- a/src/components/Reports/PeopleReport/__tests__/selectors.test.js +++ /dev/null @@ -1,291 +0,0 @@ -import { getPeopleReportData, peopleTasksPieChartViewData } from '../selectors'; - -describe('peopleTasksPieChartViewData', () => { - it('should return the correct pie chart data', () => { - const state = { - userTask: [ - { _id: '1', taskName: 'Task 1', projectId: '1', projectName: 'Project 1' }, - { _id: '2', taskName: 'Task 2', projectId: '2', projectName: 'Project 2' }, - { _id: '3', taskName: 'Task 3', projectId: '1', projectName: 'Project 1' }, - { _id: '4', taskName: 'Task 4', projectId: '3', projectName: 'Project 3' }, - { _id: '5', taskName: 'Task 5', projectId: '3', projectName: 'Project 3' }, - ], - allProjects: { - projects: [ - { _id: '1', projectName: 'Project 1' }, - { _id: '2', projectName: 'Project 2' }, - { _id: '3', projectName: 'Project 3' }, - ], - }, - timeEntries: { - period: [ - { taskId: '1', projectId: '1', hours: 5, minutes: 0, isTangible: true }, - { taskId: '2', projectId: '2', hours: 3, minutes: 0, isTangible: true }, - { taskId: '3', projectId: '1', hours: 2, minutes: 0, isTangible: true }, - { taskId: '4', projectId: '3', hours: 1, minutes: 0, isTangible: true }, - { taskId: '5', projectId: '3', hours: 0, minutes: 30, isTangible: true }, - ], - }, - }; - - const expectedData = { - tasksWithLoggedHoursById: { - '1': 5, - '2': 3, - '3': 2, - '4': 1, - '5': 0.5, - }, - projectsWithLoggedHoursById: { - 'combined_Project_1': 7, - 'combined_Project_2': 3, - 'combined_Project_3': 1.5, - }, - tasksLegend: { - '1': ['Task 1', 5], - '2': ['Task 2', 3], - '3': ['Task 3', 2], - '4': ['Task 4', 1], - '5': ['Task 5', 0.5], - }, - projectsWithLoggedHoursLegend: { - 'combined_Project_1': ['Project 1', 7], - 'combined_Project_2': ['Project 2', 3], - 'combined_Project_3': ['Project 3', 1.5], - }, - showTasksPieChart: true, - showProjectsPieChart: true, - displayedTasksWithLoggedHoursById: { - '1': 5, - '2': 3, - '3': 2, - '4': 1, - '5': 0.5, - }, - displayedTasksLegend: { - '1': ['Task 1', 5], - '2': ['Task 2', 3], - '3': ['Task 3', 2], - '4': ['Task 4', 1], - '5': ['Task 5', 0.5], - }, - showViewAllTasksButton: false, - }; - - expect(peopleTasksPieChartViewData(state)).toEqual(expectedData); - }); - - it('should handle edge case where number of tasks is exactly 5', () => { - const state = { - userTask: [ - { _id: '1', taskName: 'Task 1', projectId: '1', projectName: 'Project 1' }, - { _id: '2', taskName: 'Task 2', projectId: '2', projectName: 'Project 2' }, - { _id: '3', taskName: 'Task 3', projectId: '1', projectName: 'Project 1' }, - { _id: '4', taskName: 'Task 4', projectId: '3', projectName: 'Project 3' }, - { _id: '5', taskName: 'Task 5', projectId: '3', projectName: 'Project 3' }, - ], - allProjects: { - projects: [ - { _id: '1', projectName: 'Project 1' }, - { _id: '2', projectName: 'Project 2' }, - { _id: '3', projectName: 'Project 3' }, - ], - }, - timeEntries: { - period: [ - { taskId: '1', projectId: '1', hours: 5, minutes: 0, isTangible: true }, - { taskId: '2', projectId: '2', hours: 3, minutes: 0, isTangible: true }, - { taskId: '3', projectId: '1', hours: 2, minutes: 0, isTangible: true }, - { taskId: '4', projectId: '3', hours: 1, minutes: 0, isTangible: true }, - { taskId: '5', projectId: '3', hours: 0, minutes: 30, isTangible: true }, - ], - }, - }; - - const expectedData = { - tasksWithLoggedHoursById: { - '1': 5, - '2': 3, - '3': 2, - '4': 1, - '5': 0.5, - }, - projectsWithLoggedHoursById: { - 'combined_Project_1': 7, - 'combined_Project_2': 3, - 'combined_Project_3': 1.5, - }, - tasksLegend: { - '1': ['Task 1', 5], - '2': ['Task 2', 3], - '3': ['Task 3', 2], - '4': ['Task 4', 1], - '5': ['Task 5', 0.5], - }, - projectsWithLoggedHoursLegend: { - 'combined_Project_1': ['Project 1', 7], - 'combined_Project_2': ['Project 2', 3], - 'combined_Project_3': ['Project 3', 1.5], - }, - showTasksPieChart: true, - showProjectsPieChart: true, - displayedTasksWithLoggedHoursById: { - '1': 5, - '2': 3, - '3': 2, - '4': 1, - '5': 0.5, - }, - displayedTasksLegend: { - '1': ['Task 1', 5], - '2': ['Task 2', 3], - '3': ['Task 3', 2], - '4': ['Task 4', 1], - '5': ['Task 5', 0.5], - }, - showViewAllTasksButton: false, - }; - - expect(peopleTasksPieChartViewData(state)).toEqual(expectedData); - }); - - it('should handle case where number of tasks is greater than 5', () => { - const state = { - userTask: [ - { _id: '1', taskName: 'Task 1', projectId: '1', projectName: 'Project 1' }, - { _id: '2', taskName: 'Task 2', projectId: '2', projectName: 'Project 2' }, - { _id: '3', taskName: 'Task 3', projectId: '1', projectName: 'Project 1' }, - { _id: '4', taskName: 'Task 4', projectId: '3', projectName: 'Project 3' }, - { _id: '5', taskName: 'Task 5', projectId: '3', projectName: 'Project 3' }, - { _id: '6', taskName: 'Task 6', projectId: '3', projectName: 'Project 3' }, - ], - allProjects: { - projects: [ - { _id: '1', projectName: 'Project 1' }, - { _id: '2', projectName: 'Project 2' }, - { _id: '3', projectName: 'Project 3' }, - ], - }, - timeEntries: { - period: [ - { taskId: '1', projectId: '1', hours: 5, minutes: 0, isTangible: true }, - { taskId: '2', projectId: '2', hours: 3, minutes: 0, isTangible: true }, - { taskId: '3', projectId: '1', hours: 2, minutes: 0, isTangible: true }, - { taskId: '4', projectId: '3', hours: 1, minutes: 0, isTangible: true }, - { taskId: '5', projectId: '3', hours: 0, minutes: 30, isTangible: true }, - { taskId: '6', projectId: '3', hours: 0, minutes: 15, isTangible: true }, - ], - }, - }; - - const expectedData = { - tasksWithLoggedHoursById: { - '1': 5, - '2': 3, - '3': 2, - '4': 1, - '5': 0.5, - '6': 0.25, - }, - projectsWithLoggedHoursById: { - 'combined_Project_1': 7, - 'combined_Project_2': 3, - 'combined_Project_3': 1.75, - }, - tasksLegend: { - '1': ['Task 1', 5], - '2': ['Task 2', 3], - '3': ['Task 3', 2], - '4': ['Task 4', 1], - '5': ['Task 5', 0.5], - '6': ['Task 6', 0.25], - }, - projectsWithLoggedHoursLegend: { - 'combined_Project_1': ['Project 1', 7], - 'combined_Project_2': ['Project 2', 3], - 'combined_Project_3': ['Project 3', 1.75], - }, - showTasksPieChart: true, - showProjectsPieChart: true, - displayedTasksWithLoggedHoursById: { - '1': 5, - '2': 3, - '3': 2, - '4': 1, - otherTasksTotalHours: 0.75, - }, - displayedTasksLegend: { - '1': ['Task 1', 5], - '2': ['Task 2', 3], - '3': ['Task 3', 2], - '4': ['Task 4', 1], - otherTasksTotalHours: ['2 other tasks', 0.75], - }, - showViewAllTasksButton: true, - }; - - expect(peopleTasksPieChartViewData(state)).toEqual(expectedData); - }); -}); - -describe('getPeopleReportData', () => { - it('should return the correct data from state', () => { - const state = { - auth: { isAuthenticated: true }, - userProfile: { - name: 'John Doe', - tangibleHoursReportedThisWeek: '10.5', - infringements: [] - }, - userTask: [{ id: 1, name: 'Task 1' }], - user: { id: 1, name: 'John Doe' }, - timeEntries: { - period: [ - { id: 1, hours: 5, minutes: 0, isTangible: true } - ] - }, - userProjects: [{ id: 1, name: 'Project 1' }], - allProjects: { projects: [{ id: 1, name: 'Project 1' }] }, - isAssigned: true, - isActive: true, - priority: 'High', - status: 'Active', - hasFilter: true, - allClassification: ['Class 1', 'Class 2'], - classification: 'Class 1', - users: [{ id: 1, name: 'John Doe' }], - classificationList: ['Class 1', 'Class 2'], - priorityList: ['High', 'Medium', 'Low'], - statusList: ['Active', 'Inactive'], - theme: { darkMode: true }, - }; - - const expectedData = { - auth: state.auth, - userProfile: state.userProfile, - userTask: state.userTask, - infringements: state.userProfile.infringements, - user: state.user, - timeEntries: state.timeEntries, - totalTangibleHours: 5, - userProjects: state.userProjects, - allProjects: state.allProjects, - allTeams: state, - isAssigned: state.isAssigned, - isActive: state.isActive, - priority: state.priority, - status: state.status, - hasFilter: state.hasFilter, - allClassification: state.allClassification, - classification: state.classification, - users: state.users, - classificationList: state.classificationList, - priorityList: state.priorityList, - statusList: state.statusList, - tangibleHoursReportedThisWeek: parseFloat(state.userProfile.tangibleHoursReportedThisWeek), - darkMode: state.theme.darkMode, - }; - - expect(getPeopleReportData(state)).toEqual(expectedData); - }); -}); \ No newline at end of file diff --git a/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.jsx b/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.jsx index 7a2a01b570..ced21400f6 100644 --- a/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.jsx +++ b/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.jsx @@ -1,10 +1,11 @@ /* eslint-disable import/prefer-default-export */ -import { useState } from 'react'; import { useSelector } from 'react-redux'; import { PieChart } from '../../../common/PieChart'; +import { UserProjectPieChart } from '../../../common/PieChart/ProjectPieChart'; import { peopleTasksPieChartViewData } from '../selectors'; import { ReportPage } from '../../sharedComponents/ReportPage'; import './PeopleTasksPieChart.css'; +// import { ProjectPieChart } from 'components/Reports/ProjectReport/ProjectPieChart/ProjectPieChart'; export function PeopleTasksPieChart({ darkMode }) { const { @@ -12,35 +13,31 @@ export function PeopleTasksPieChart({ darkMode }) { showTasksPieChart, showProjectsPieChart, tasksLegend, - projectsWithLoggedHoursById, - projectsWithLoggedHoursLegend, - displayedTasksLegend, showViewAllTasksButton, + hoursLoggedToProjectsOnly, } = useSelector(peopleTasksPieChartViewData); - - const [showAllTasks, setShowAllTasks] = useState(false); + + // const [showAllTasks, setShowAllTasks] = useState(false); if (!showTasksPieChart && !showProjectsPieChart) { return null; } - function handleViewAll() { - setShowAllTasks(prev => !prev); - } + // function handleViewAll() { + // setShowAllTasks(prev => !prev); + // } return (
- {showProjectsPieChart && ( + {hoursLoggedToProjectsOnly.length!==0 && (
Projects With Completed Hours
- + projectsData={hoursLoggedToProjectsOnly} + tasksData={tasksLegend} + />}
)} {showTasksPieChart && ( @@ -50,19 +47,18 @@ export function PeopleTasksPieChart({ darkMode }) { }Tasks With Completed Hours`} - {showViewAllTasksButton && ( + {/* {showViewAllTasksButton && (
{showAllTasks ? 'Collapse' : 'View all'}
- )} + )} */} )}
diff --git a/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.test.jsx b/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.test.jsx deleted file mode 100644 index 3b3e8234dd..0000000000 --- a/src/components/Reports/PeopleReport/components/PeopleTasksPieChart.test.jsx +++ /dev/null @@ -1,131 +0,0 @@ -import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; -import { useSelector } from 'react-redux'; -import { PeopleTasksPieChart } from './PeopleTasksPieChart'; - -// Mock useSelector -jest.mock('react-redux', () => ({ - useSelector: jest.fn(), -})); - -describe('PeopleTasksPieChart', () => { - beforeEach(() => { - useSelector.mockClear(); - }); - - const defaultSelectorData = { - tasksWithLoggedHoursById: { task1: 10, task2: 20 }, - showTasksPieChart: true, - showProjectsPieChart: false, - tasksLegend: { - task1: ['Task 1', '10 hours'], - task2: ['Task 2', '20 hours'], - }, - projectsWithLoggedHoursById: {}, - projectsWithLoggedHoursLegend: {}, - displayedTasksWithLoggedHoursById: { task1: 10, task2: 20 }, - displayedTasksLegend: { - task1: ['Task 1', '10 hours'], - task2: ['Task 2', '20 hours'], - }, - showViewAllTasksButton: true, - }; - - it('renders PieChart for tasks when showTasksPieChart is true', () => { - useSelector.mockReturnValue(defaultSelectorData); - - render(); - - expect(screen.getByText(/Tasks With Completed Hours/i)).toBeInTheDocument(); - }); - - it('renders without crashing when showTasksPieChart and showProjectsPieChart are false', () => { - useSelector.mockReturnValue({ - ...defaultSelectorData, - showTasksPieChart: false, - showProjectsPieChart: false, - }); - - const { container } = render(); - expect(container.firstChild).toBeNull(); - }); - - it('renders PieChart for projects when showProjectsPieChart is true', () => { - useSelector.mockReturnValue({ - ...defaultSelectorData, - showProjectsPieChart: true, - }); - - render(); - - expect(screen.getByText('Projects With Completed Hours')).toBeInTheDocument(); - }); - - it('renders in dark mode when darkMode prop is true', () => { - useSelector.mockReturnValue(defaultSelectorData); - - const { container } = render(); - expect(container.firstChild).toHaveClass('text-light'); - }); - - it('toggles "View all" button correctly', () => { - useSelector.mockReturnValue(defaultSelectorData); - - render(); - - const viewAllButton = screen.getByText('View all'); - expect(viewAllButton).toBeInTheDocument(); - - fireEvent.click(viewAllButton); - - expect(screen.getByText('Collapse')).toBeInTheDocument(); - }); - - it('does not show "View all" button when showViewAllTasksButton is false', () => { - useSelector.mockReturnValue({ - ...defaultSelectorData, - showViewAllTasksButton: false, - }); - - render(); - - expect(screen.queryByText('View all')).not.toBeInTheDocument(); - }); - - it('displays total hours as 0.00 when there is no task data', () => { - useSelector.mockReturnValue({ - ...defaultSelectorData, - tasksWithLoggedHoursById: {}, - displayedTasksWithLoggedHoursById: {}, - }); - - render(); - - expect(screen.getByText('Total Hours : 0.00')).toBeInTheDocument(); - }); - - it('displays correct legend information for tasks', () => { - useSelector.mockReturnValue(defaultSelectorData); - - render(); - - expect(screen.getByText('Task 1')).toBeInTheDocument(); - expect(screen.getByText('10 hours')).toBeInTheDocument(); - expect(screen.getByText('Task 2')).toBeInTheDocument(); - expect(screen.getByText('20 hours')).toBeInTheDocument(); - }); - - it('renders PieChart for tasks and projects based on their respective flags', () => { - useSelector.mockReturnValue({ - ...defaultSelectorData, - showTasksPieChart: true, - showProjectsPieChart: true, - }); - - render(); - - expect(screen.getByText(/Tasks With Completed Hours/i)).toBeInTheDocument(); - expect(screen.getByText('Projects With Completed Hours')).toBeInTheDocument(); - }); - -}); diff --git a/src/components/Reports/PeopleReport/selectors.js b/src/components/Reports/PeopleReport/selectors.js index 7fa3ebbabd..1cb74e3d9f 100644 --- a/src/components/Reports/PeopleReport/selectors.js +++ b/src/components/Reports/PeopleReport/selectors.js @@ -1,20 +1,5 @@ import _ from 'lodash'; -export const calculateTotalTangibleHours = (timeEntries) => { - if (!Array.isArray(timeEntries.period)) { - return 0; - } - - return timeEntries.period.reduce((total, entry) => { - if (!entry.isTangible) { - return total; - } - const hours = Number(entry.hours) || 0; - const minutes = Number(entry.minutes) || 0; - return total + hours + (minutes / 60); - }, 0); -}; - export const getPeopleReportData = state => ({ auth: state.auth, userProfile: state.userProfile, @@ -22,7 +7,6 @@ export const getPeopleReportData = state => ({ infringements: state.userProfile.infringements, user: _.get(state, 'user', {}), timeEntries: state.timeEntries, - totalTangibleHours: calculateTotalTangibleHours(state.timeEntries), userProjects: state.userProjects, allProjects: _.get(state, 'allProjects'), allTeams: state, @@ -41,187 +25,62 @@ export const getPeopleReportData = state => ({ darkMode: state.theme.darkMode, }); -const getRounded = number => { - return Math.round(number * 100) / 100; -}; - -export const peopleTasksPieChartViewData = ({ - userTask = [], - allProjects = {}, - timeEntries = {}, -}) => { - const tasksWithLoggedHoursById = {}; - const projectsWithLoggedHoursById = {}; - const projectNameMapping = {}; - const tasksLegend = {}; - const projectsWithLoggedHoursLegend = {}; - - // Create a mapping of task IDs to task names - const taskNameMapping = {}; - userTask.forEach(task => { - taskNameMapping[task._id] = task.taskName; - if (task.projectId && task.projectName) { - projectNameMapping[task.projectId] = task.projectName; +export const peopleTasksPieChartViewData = ({userProjects,timeEntries }) => { + + let hoursLoggedToProjectsOnly = {}; + const tasksWithLoggedHoursOnly = {}; + // let totalHours = 0; + // for(let i=0; i{ + if(entry.wbsId===null){ + hoursLoggedToProjectsOnly[entry.projectId] = hoursLoggedToProjectsOnly[entry.projectId] ? hoursLoggedToProjectsOnly[entry.projectId] + entry.hours+(entry.minutes/60) : entry.hours+(entry.minutes/60); } - }); - - // Only count tangible hours for the pie chart - if (Array.isArray(timeEntries.period)) { - timeEntries.period.forEach((entry) => { - // Skip non-tangible entries or entries without a project - if (!entry.isTangible || !entry.projectId) { - return; - } - - const { taskId, projectId, hours = 0, minutes = 0, projectName, taskName } = entry; - - // Convert hours and minutes to total hours - const totalHours = Number(hours) + (Number(minutes) / 60); - - const taskKey = (() => { - if (!taskId) return null; - return typeof taskId === 'object' ? taskId._id : taskId; - })(); - - const projectKey = (() => { - if (!projectId) return null; - return typeof projectId === 'object' ? projectId._id : projectId; - })(); - - // Only accumulate hours for tasks that have a valid project - if (taskKey && projectKey) { - tasksWithLoggedHoursById[taskKey] = - (tasksWithLoggedHoursById[taskKey] || 0) + totalHours; - - // Store task name if available - if (taskName) { - taskNameMapping[taskKey] = taskName; - } - } - - // Store project name if available - if (projectKey && projectName) { - projectNameMapping[projectKey] = projectName; - } - - // Accumulate tangible project hours - if (projectKey) { - projectsWithLoggedHoursById[projectKey] = - (projectsWithLoggedHoursById[projectKey] || 0) + totalHours; - } - }); - } - - // Build the projects legend with proper names - Object.entries(projectsWithLoggedHoursById).forEach( - ([projectId, totalHours]) => { - // Try to get project name from multiple sources - const projectName = - projectNameMapping[projectId] || // From our mapping - allProjects?.projects?.find(p => p._id === projectId)?.projectName || // From allProjects - 'Untitled Project'; - - projectsWithLoggedHoursLegend[projectId] = [ - projectName, - getRounded(totalHours), - ]; - }, - ); - - // Combine projects with the same name (handle duplicates) - const combinedProjects = {}; - Object.entries(projectsWithLoggedHoursLegend).forEach(([, [name, hours]]) => { - if (!combinedProjects[name]) { - combinedProjects[name] = hours; - } else { - combinedProjects[name] += hours; + }) + + timeEntries.period.forEach(entry=>{ + if(entry.wbsId!==null){ + tasksWithLoggedHoursOnly[entry.projectId] = tasksWithLoggedHoursOnly[entry.projectId] ? tasksWithLoggedHoursOnly[entry.projectId] + entry.hours+(entry.minutes/60) : entry.hours+(entry.minutes/60); } - }); - - // Rebuild projectsWithLoggedHoursById and legend with combined values - const newProjectsWithLoggedHoursById = {}; - const newProjectsWithLoggedHoursLegend = {}; + }) - Object.entries(combinedProjects).forEach(([name, hours]) => { - const id = `combined_${name.replace(/\s+/g, '_')}`; - newProjectsWithLoggedHoursById[id] = hours; - newProjectsWithLoggedHoursLegend[id] = [name, getRounded(hours)]; + + const resultArray = Object.keys(hoursLoggedToProjectsOnly).map(projectId => { + const project = userProjects?.projects.find(proj => proj.projectId === projectId); + return { + projectId, + projectName: project ? project.projectName : "Unknown", // Use "Unknown" if no matching project is found + totalTime: hoursLoggedToProjectsOnly[projectId] + }; }); - // Build a consistent array of tasks (with total hours) we can sort, slice, etc. - const tasksWithLoggedHours = Object.entries(tasksWithLoggedHoursById).map( - ([taskId, totalHours]) => { - // Look up task name from our mapping or userTask array - const taskName = taskNameMapping[taskId] || - userTask.find(t => t._id === taskId)?.taskName || - 'Untitled Task'; - - return { - _id: taskId, - hoursLogged: totalHours, - taskName, - projectId: userTask.find(t => t._id === taskId)?.projectId, - }; - }, - ); - - // Sort descending by hours - tasksWithLoggedHours.sort((a, b) => b.hoursLogged - a.hoursLogged); - - // Build tasks legend from tasksWithLoggedHours - tasksWithLoggedHours.forEach(({ _id, hoursLogged, taskName }) => { - tasksLegend[_id] = [taskName, getRounded(hoursLogged)]; + const resultArray2 = Object.keys(tasksWithLoggedHoursOnly).map(projectId => { + const project = userProjects?.projects.find(proj => proj.projectId === projectId); + return { + projectId, + projectName: project ? project.projectName : "Unknown", // Use "Unknown" if no matching project is found + totalTime: tasksWithLoggedHoursOnly[projectId] + }; }); + + hoursLoggedToProjectsOnly = resultArray; - // Decide how many tasks we want to display before grouping them as "Other Tasks" - const displayedTasksCount = Math.max( - 4, - Object.keys(newProjectsWithLoggedHoursById).length, - ); - - // Minimal chart data + let tasksWithLoggedHoursById = {}; const displayedTasksWithLoggedHoursById = {}; + const projectsWithLoggedHoursById = {}; + let tasksLegend = {}; const displayedTasksLegend = {}; - // Take the top (displayedTasksCount) tasks - tasksWithLoggedHours.slice(0, displayedTasksCount).forEach(task => { - displayedTasksWithLoggedHoursById[task._id] = task.hoursLogged; - displayedTasksLegend[task._id] = [ - task.taskName, - getRounded(task.hoursLogged), - ]; - }); - - // If there are more tasks than displayedTasksCount, handle "other tasks" logic - if (tasksWithLoggedHours.length > displayedTasksCount) { - if (tasksWithLoggedHours.length === displayedTasksCount + 1) { - const remainder = tasksWithLoggedHours.slice(displayedTasksCount); - remainder.forEach(({ _id, hoursLogged, taskName }) => { - displayedTasksWithLoggedHoursById[_id] = hoursLogged; - displayedTasksLegend[_id] = [taskName, getRounded(hoursLogged)]; - }); - } else { - const remainder = tasksWithLoggedHours.slice(displayedTasksCount); - const totalOtherHours = remainder.reduce( - (acc, val) => acc + val.hoursLogged, - 0, - ); - const numberOtherTasks = remainder.length; - displayedTasksWithLoggedHoursById.otherTasksTotalHours = totalOtherHours; - displayedTasksLegend.otherTasksTotalHours = [ - `${numberOtherTasks} other tasks`, - getRounded(totalOtherHours), - ]; - } - } - + tasksLegend=resultArray2; + tasksWithLoggedHoursById=resultArray2; return { + hoursLoggedToProjectsOnly, tasksWithLoggedHoursById, - projectsWithLoggedHoursById: newProjectsWithLoggedHoursById, tasksLegend, - projectsWithLoggedHoursLegend: newProjectsWithLoggedHoursLegend, showTasksPieChart: Object.keys(tasksWithLoggedHoursById).length > 0, - showProjectsPieChart: Object.keys(newProjectsWithLoggedHoursById).length > 0, + showProjectsPieChart: Object.keys(projectsWithLoggedHoursById).length > 0, displayedTasksWithLoggedHoursById, displayedTasksLegend, showViewAllTasksButton: diff --git a/src/components/Reports/PeopleTableDetails.jsx b/src/components/Reports/PeopleTableDetails.jsx index b8d85197fa..da6d00ab24 100644 --- a/src/components/Reports/PeopleTableDetails.jsx +++ b/src/components/Reports/PeopleTableDetails.jsx @@ -15,25 +15,9 @@ function PeopleTableDetails(props) { const [assign, setAssign] = useState(''); const [estimatedHours, setEstimatedHours] = useState(''); const [order, setOrder] = useState(''); - const [startDate] = useState(''); - const [endDate] = useState(''); - + const [startDate,updateStartDate] = useState(new Date('01/01/2010')); + const [endDate, updateEndDate] = useState(new Date()); const [windowWidth, setWindowWidth] = useState(window.innerWidth); - // useEffect(() => { - // function handleResize() { - // const w = window.innerWidth - // if (w <= 1020) { - // setisMobile(true); - // } else { - // setisMobile(false) - // } - // } - // window.addEventListener('resize', handleResize); - - // return () => { - // window.removeEventListener('resize', handleResize); - // }; - // }, []); useEffect(() => { const handleResize = () => { @@ -82,6 +66,8 @@ function PeopleTableDetails(props) { setActive(''); setAssign(''); setEstimatedHours(''); + updateStartDate(new Date('01/01/2010')); + updateEndDate(new Date()); }; const filterOptions = tasks => { @@ -108,13 +94,22 @@ function PeopleTableDetails(props) { const simple = []; // eslint-disable-next-line array-callback-return,consistent-return let filteredList = tasks.filter(task => { + // Convert task dates to Date objects for comparison + const taskStartDate = new Date(task.startDate); + // const taskEndDate = new Date(task.endDate); + + // Check if dates are within the selected range + const isWithinDateRange = (!startDate || taskStartDate <= endDate) + // && (!endDate || taskEndDate <= endDate); + if ( task.taskName.toLowerCase().includes(name.toLowerCase()) && task?.priority?.toLowerCase().includes(priority.toLowerCase()) && task?.status?.toLowerCase().includes(status.toLowerCase()) && task?.active?.toLowerCase().includes(active.toLowerCase()) && task?.estimatedHours?.toLowerCase().includes(estimatedHours.toLowerCase()) && - task?.assign?.toLowerCase().includes(assign.toLowerCase()) + task?.assign?.toLowerCase().includes(assign.toLowerCase()) && + isWithinDateRange ) { return true; } @@ -175,7 +170,7 @@ function PeopleTableDetails(props) { if (index < 2) { return ( {resource.name} ( - + // ) return ( @@ -307,8 +302,10 @@ function PeopleTableDetails(props) { active={active} assign={assign} estimatedHours={estimatedHours} - startDate={startDate} + StartDate={startDate} + UpdateStartDate={updateStartDate} EndDate={endDate} + UpdateEndDate={updateEndDate} />
{filteredTasks.map(value => ( + // eslint-disable-next-line react/no-unstable-nested-components <> {(windowWidth <= 1020) ? renderMobileFilteredTask(value) : renderFilteredTask(value)}}>
Why This Task is important
diff --git a/src/components/Reports/Reports.jsx b/src/components/Reports/Reports.jsx index 25bb5ddf61..e8682cdae3 100644 --- a/src/components/Reports/Reports.jsx +++ b/src/components/Reports/Reports.jsx @@ -538,8 +538,9 @@ class ReportsPage extends Component { />
-
-
-
-
+
+ + {myRole !== 'Owner' && (
diff --git a/src/components/Reports/TableFilter/TableFilter.jsx b/src/components/Reports/TableFilter/TableFilter.jsx index d0e7d068c8..04e49a0a92 100644 --- a/src/components/Reports/TableFilter/TableFilter.jsx +++ b/src/components/Reports/TableFilter/TableFilter.jsx @@ -37,13 +37,17 @@ function TableFilter({ resources, status, priority, + StartDate, + EndDate, + UpdateStartDate, + UpdateEndDate, }) { const taskPriority = ['Primary', 'Secondary', 'Tertiary']; const taskStatus = ['Paused', 'Complete', 'Active']; const [taskActive, setTaskActive] = useState(true); const [taskAssign, setTaskAssign] = useState(true); - const [startDate, setStartDate] = useState(new Date('01/01/2010')); - const [endDate, setEndDate] = useState(new Date()); + // const [startDate, setStartDate] = useState(new Date('01/01/2010')); + // const [endDate, setEndDate] = useState(new Date()); const taskName = taskNameList.map((item) => item.taskName) const taskHour = taskNameList.map((item) => item.estimatedHours) const taskResource = taskNameList.map(function taskResource(item) { return [item.resources.map((e) => e[0].name)].join() }) @@ -95,17 +99,17 @@ function TableFilter({ /> } - selected={startDate} + selected={StartDate} minDate={new Date('01/01/2010')} maxDate={new Date()} - onChange={date => setStartDate(date)} + onChange={date => UpdateStartDate(date)} /> } - selected={endDate} + selected={EndDate} maxDate={new Date()} minDate={new Date('01/01/2010')} - onChange={date => setEndDate(date)} + onChange={date => UpdateEndDate(date)} /> state.auth.user.userid; -const selectUpdateTaskData = (state, taskId) => +export const selectFetchTeamMembersTaskData = state => state.auth.user.userid; +export const selectUpdateTaskData = (state, taskId) => state.tasks.taskItems.find(({ _id }) => _id === taskId); -export const fetchTaskEditSuggestions = () => async (dispatch, getState) => { +export const fetchTaskEditSuggestions = () => async dispatch => { try { dispatch(fetchTaskEditSuggestionsBegin()); const response = await getTaskEditSuggestionsHTTP(); @@ -24,11 +21,11 @@ export const fetchTaskEditSuggestions = () => async (dispatch, getState) => { } }; -export const fetchTaskEditSuggestionCount = () => async (dispatch, getState) => { +export const fetchTaskEditSuggestionCount = () => async dispatch => { try { const response = await getTaskEditSuggestionCountHTTP(); dispatch(fetchTaskEditSuggestionCountSuccess(response.data.count)); } catch (error) { - console.log(`fetch task edit suggestion count thunk error\n${ error}`); + toast.info(`fetch task edit suggestion count thunk error\n${error}`); } }; diff --git a/src/components/UserManagement/DropDownSearchBox.jsx b/src/components/UserManagement/DropDownSearchBox.jsx index 0ab9466420..636647bda5 100644 --- a/src/components/UserManagement/DropDownSearchBox.jsx +++ b/src/components/UserManagement/DropDownSearchBox.jsx @@ -32,6 +32,7 @@ class DropDownSearchBox extends React.PureComponent { + {this.props.items.map((item, index) => { return (