Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/components/Header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export function Header(props) {
const [displayUserId, setDisplayUserId] = useState(user.userid);
const [popup, setPopup] = useState(false);
const [isAuthUser, setIsAuthUser] = useState(true);
const [isAckLoading, setIsAckLoading] = useState(false);
const [ showPromotionsPopup, setShowPromotionsPopup ] = useState(false);

const ALLOWED_ROLES_TO_INTERACT = useMemo(() => ['Owner', 'Administrator'], []);
Expand Down
94 changes: 67 additions & 27 deletions src/components/Reports/LostTime/AddLostTime.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import '../../Header/DarkMode.css'
import { isEmpty, isEqual } from 'lodash';
import { getUserProfile } from '~/actions/userProfile';
import { postTimeEntry } from '~/actions/timeEntries';
import { toast } from 'react-toastify';

function AddLostTime(props) {

const darkMode = useSelector((state) => state.theme.darkMode);
const fontColor = getFontColor(darkMode);
const boxStyling = getBoxStyling(darkMode);
const MAX_HOURS_PER_ENTRY = 40;

const initialForm = {
projectId: undefined,
Expand Down Expand Up @@ -234,51 +236,89 @@ function AddLostTime(props) {
props.toggle();
};

const validateInputs = () => {
const result = {};

const date = moment(inputs.dateOfWork);
const validateDate = (dateOfWork) => {
const errors = {};
const date = moment(dateOfWork);
const today = moment(
moment()
.tz('America/Los_Angeles')
.format('YYYY-MM-DD'),
);

if (!date.isValid()) {
result.dateOfWork = 'Invalid date';
} else if (
today.diff(date, 'days') < 0
) {
result.dateOfWork = 'Cannot add lost time for future dates.';
errors.dateOfWork = 'Invalid date';
} else if (today.diff(date, 'days') < 0) {
errors.dateOfWork = 'Cannot add lost time for future dates.';
}

if (inputs.hours === 0 && inputs.minutes === 0) {
result.time = 'Time is required';
} else {
const hours = inputs.hours * 1;
const minutes = inputs.minutes * 1;
if (!Number.isInteger(hours) || !Number.isInteger(minutes)) {
result.time = 'Hours and minutes should be integers';
}
if (hours < 0 || minutes < 0) {
result.time = 'Time should be greater than 0';
}
return errors;
};

const getTimeError = (hoursInput, minutesInput) => {
const hours = Number(hoursInput);
const minutes = Number(minutesInput);

if (Number.isNaN(hours) || Number.isNaN(minutes) || (hours === 0 && minutes === 0)) {
return 'Time is required';
}

if (!Number.isInteger(hours) || !Number.isInteger(minutes)) {
return 'Hours and minutes should be integers';
}

if (hours < 0 || minutes < 0) {
return 'Time should be greater than 0';
}

const totalMinutes = hours * 60 + minutes;
const maxMinutes = MAX_HOURS_PER_ENTRY * 60;

if (totalMinutes > maxMinutes) {
toast.error(
"Hold up, workhorse! You’ve hit the 40-hour limit for a single entry. You can pop in a new time log for any additional hours.",
{ autoClose: 5000 }
);
return `You can’t log more than ${MAX_HOURS_PER_ENTRY} hours in a single entry.`;
}

return null;
};

const validateEntryType = (entryType, inputs) => {
const errors = {};

if (entryType === '') {
result.events = 'Type is required';
errors.events = 'Type is required';
return errors;
}

if (entryType === 'project' && inputs.projectId === undefined) {
result.projectId = 'Project is required';
errors.projectId = 'Project is required';
} else if (entryType === 'person' && inputs.personId === undefined) {
errors.personId = 'Person is required';
} else if (entryType === 'team' && inputs.teamId === undefined) {
errors.teamId = 'Team is required';
}
if (entryType === 'person' && inputs.personId === undefined) {
result.personId = 'Person is required';
}
if (entryType === 'team' && inputs.teamId === undefined) {
result.teamId = 'Team is required';

return errors;
};

const validateInputs = () => {
const result = {};

Object.assign(result, validateDate(inputs.dateOfWork));

const timeError = getTimeError(inputs.hours, inputs.minutes);
if (timeError) {
result.time = timeError;
}

Object.assign(result, validateEntryType(entryType, inputs));

setErrors(result);
return isEmpty(result);
};


const handleSubmit = async event => {
if (event) event.preventDefault();
Expand Down
101 changes: 72 additions & 29 deletions src/components/Reports/LostTime/EditHistoryModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
import { deleteTimeEntry, editTimeEntry } from '~/actions/timeEntries';
import './EditHistoryModal.css';
import '../../Header/DarkMode.css'
import { toast } from 'react-toastify';

function EditHistoryModal(props) {
const {darkMode} = props;
const fontColor = getFontColor(darkMode);
const boxStyling = getBoxStyling(darkMode);
const MAX_HOURS_PER_ENTRY = 40;

const initialForm = {
projectId: props.entryType === 'project'? props.dataId: undefined,
Expand Down Expand Up @@ -110,50 +112,91 @@
toggleEdit();
};

const validateInputs = () => {
const result = {};

const date = moment(inputs.dateOfWork);
const validateDate = (dateOfWork) => {
const errors = {};
const date = moment(dateOfWork);
const today = moment(
moment()
.tz('America/Los_Angeles')
.format('YYYY-MM-DD'),
);

if (!date.isValid()) {
result.dateOfWork = 'Invalid date';
} else if (
today.diff(date, 'days') < 0
errors.dateOfWork = 'Invalid date';
} else if (today.diff(date, 'days') < 0) {
errors.dateOfWork = 'Cannot add lost time for future dates.';
}

return errors;
};

const validateTime = (hoursInput, minutesInput) => {
const errors = {};
const hours = Number(hoursInput);
const minutes = Number(minutesInput);

if (
Number.isNaN(hours) ||
Number.isNaN(minutes) ||
(hours === 0 && minutes === 0)
) {
result.dateOfWork = 'Cannot add lost time for future dates.';
errors.time = 'Time is required';
return errors;
}

if (inputs.hours === 0 && inputs.minutes === 0) {
result.time = 'Time is required';
} else {
const hours = inputs.hours * 1;
const minutes = inputs.minutes * 1;
if (!Number.isInteger(hours) || !Number.isInteger(minutes)) {
result.time = 'Hours and minutes should be integers';
}
if (hours < 0 || minutes < 0) {
result.time = 'Time should be greater than 0';
}

if (!Number.isInteger(hours) || !Number.isInteger(minutes)) {
errors.time = 'Hours and minutes should be integers';
return errors;
}

if (props.entryType === 'project' && inputs.projectId === undefined) {
result.projectId = 'Project is required';

if (hours < 0 || minutes < 0) {
errors.time = 'Time should be greater than 0';
return errors;
}
if (props.entryType === 'person' && inputs.personId === undefined) {
result.personId = 'Person is required';

const totalMinutes = hours * 60 + minutes;
const maxMinutes = MAX_HOURS_PER_ENTRY * 60;

if (totalMinutes > maxMinutes) {
errors.time = `You can’t log more than ${MAX_HOURS_PER_ENTRY} hours in a single entry.`;
toast.error(
"Hold up, workhorse! You’ve hit the 40-hour limit for a single entry. You can pop in a new time log for any additional hours.",
{ autoClose: 5000 }
);
}
if (props.entryType === 'team' && inputs.teamId === undefined) {
result.teamId = 'Team is required';

return errors;
};

const validateEntryType = (inputs, entryType) => {
const errors = {};

if (entryType === 'project' && inputs.projectId === undefined) {
errors.projectId = 'Project is required';
} else if (entryType === 'person' && inputs.personId === undefined) {
errors.personId = 'Person is required';
} else if (entryType === 'team' && inputs.teamId === undefined) {
errors.teamId = 'Team is required';
}


return errors;
};

const validateInputs = () => {
const dateErrors = validateDate(inputs.dateOfWork);
const timeErrors = validateTime(inputs.hours, inputs.minutes);
const entryTypeErrors = validateEntryType(inputs, props.entryType);

Check warning on line 188 in src/components/Reports/LostTime/EditHistoryModal.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'entryType' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZrXk2sLs0OCvQ2jr49K&open=AZrXk2sLs0OCvQ2jr49K&pullRequest=4465

const result = {
...dateErrors,
...timeErrors,
...entryTypeErrors,
};

setErrors(result);
return isEmpty(result);
};

const handleSubmit = async event => {

if (event) event.preventDefault();
Expand Down
Loading