Skip to content
Open
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
18 changes: 16 additions & 2 deletions src/actions/information.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,28 @@ export const updateInfoSuccess = updatedInfo => ({
payload: updatedInfo,
});

export const fetchInfosBegin = () => ({
type: actions.FETCH_INFOS_BEGIN,
});

export const fetchInfosError = () => ({
type: actions.FETCH_INFOS_ERROR,
})

// Get infoCollections
export const getInfoCollections = () => {
return async dispatch => {
export const getInfoCollections = (retrieveInfos=false) => {
return async (dispatch, getState) => {
try {
const { infoCollections } = getState();
if (!retrieveInfos && (infoCollections.loading || infoCollections.loaded)) {
return;
}
dispatch(fetchInfosBegin())
const response = await axios.get(ENDPOINTS.INFO_COLLECTIONS);
dispatch(fetchInfosSuccess(response.data));
return response.data;
} catch (error) {
dispatch(fetchInfosError)
toast.error(error.message || 'Failed to fetch info collections.');
return null;
}
Expand Down
20 changes: 12 additions & 8 deletions src/components/TeamMemberTasks/TeamMemberTask.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ const TeamMemberTask = React.memo(
const canUnassignTask = dispatch(hasPermission(permissions.removeUserFromTask));
const numTasksToShow = isTruncated ? NUM_TASKS_SHOW_TRUNCATE : activeTasks.length;

const tableRowDarkMode = () => {
if (darkMode) return `${styles['table-row']} ${styles.darkMode} bg-yinmn-blue`;
return `${styles['table-row']}`;
};

const colorsObjs = {
'Assistant Manager': '#849ced', // blue
Manager: '#90e766', // green
Expand Down Expand Up @@ -256,11 +261,7 @@ const TeamMemberTask = React.memo(
};

return (
<tr
ref={ref}
className={`${styles['table-row']} ${darkMode ? 'bg-yinmn-blue' : ''}`}
key={user.personId}
>
<tr ref={ref} className={tableRowDarkMode()} key={user.personId}>
<td className={styles['remove-padding']} colSpan={6}>
<div className={styles['row-content']}>
{isTimeOffContentOpen && (
Expand Down Expand Up @@ -298,7 +299,7 @@ const TeamMemberTask = React.memo(
)}
<Table className={styles['no-bottom-margin']}>
<tbody>
<tr className="remove-child-borders">
<tr className={`remove-child-borders ${darkMode ? styles.darkMode : ''}`}>
{/* green if member has met committed hours for the week, red if not */}
<td colSpan={1} className={`${darkMode ? 'bg-yinmn-blue' : ''}`}>
<div style={{ display: 'flex', flexWrap: 'wrap', flexDirection: 'column' }}>
Expand Down Expand Up @@ -416,7 +417,10 @@ const TeamMemberTask = React.memo(
style={{ margin: '0 auto', width: '100%' }}
>
<tbody>
<tr style={{ width: '500px' }}>
<tr
className={`${darkMode ? styles.darkMode : ''}`}
style={{ width: '500px' }}
>
<td
colSpan={2}
className={styles['team-member-tasks-user-name']}
Expand Down Expand Up @@ -583,7 +587,7 @@ const TeamMemberTask = React.memo(
<tr
key={`${task._id}`}
className={`${styles['task-break']} ${
darkMode ? 'bg-yinmn-blue' : ''
darkMode ? `${styles.darkMode} bg-yinmn-blue` : ''
}`}
>
<td
Expand Down
7 changes: 5 additions & 2 deletions src/components/TeamMemberTasks/style.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@
vertical-align: stretch !important;
}

tr.darkMode:hover {
background: #2f4157 !important;
}

.hidden {
visibility: hidden;
}
Expand Down Expand Up @@ -836,8 +840,7 @@
}

.table-row {
border: solid #e9ecef 2px;
background: #faf7fc;
border: solid #3a506b 2px;
font-size: 0.75rem !important;
}

Expand Down
23 changes: 14 additions & 9 deletions src/components/UserProfile/EditableModal/EditableInfoModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class EditableInfoModal extends Component {

// ✅ Centralized: derive modal state from collections + props
deriveFromCollections = infoCollections => {
const { role, areaName, fontSize, isPermissionPage } = this.props;
const { role, areaName, fontSize, isPermissionPage, initialInfo } = this.props;

let content = '';
let visible = '0';
Expand All @@ -101,13 +101,16 @@ export class EditableInfoModal extends Component {
(visible === '2' && role !== 'Volunteer');

const CanEdit = role === 'Owner';

const contentToDisplay = () => {
if (content) return content;
return initialInfo ? this.sanitizeText(initialInfo) : 'Please input information!';
};
return {
infoElements: Array.isArray(infoCollections) ? [...infoCollections] : [],
fetchError: this.props.fetchError,
loading: this.props.loading,
infoName: areaName,
infoContent: content || 'Please input information!',
infoContent: contentToDisplay(),
visibility: visible,
CanRead,
CanEdit,
Expand Down Expand Up @@ -231,7 +234,7 @@ export class EditableInfoModal extends Component {
if (saveResult === 200 || saveResult === 201) {
await this.handleSaveSuccess();
// ✅ Refresh collections so UI is always in sync
this.props.getInfoCollections();
this.props.getInfoCollections(true);
} else {
this.handleSaveError();
}
Expand All @@ -241,7 +244,7 @@ export class EditableInfoModal extends Component {
const { infoId } = this.handleChangeInInfos();
await this.props.deleteInfoCollectionById(infoId);
// Refresh collections after delete
this.props.getInfoCollections();
this.props.getInfoCollections(true);
};

handleClose = () => {
Expand All @@ -260,7 +263,7 @@ export class EditableInfoModal extends Component {
const { darkMode } = this.props;
const headerDarkClass = darkMode ? `${appStyles['bg-space-cadet']} text-light` : '';

const sanitizedContent = infoContent;
const sanitizedContent = infoContent;

return (
CanRead && (
Expand All @@ -269,9 +272,9 @@ export class EditableInfoModal extends Component {
data-toggle="tooltip"
data-placement="right"
title="Click for information about this"
style={{ fontSize: fontSize, cursor: 'pointer', color: '#00CCFF', marginRight: '8px' }}
style={{ fontSize: fontSize }}
aria-hidden="true"
className="fa fa-info-circle"
className={`fa fa-info-circle ${styles.infoIcon}`}
onClick={() => this.setState({ editableModalOpen: true })}
/>

Expand Down Expand Up @@ -321,6 +324,7 @@ export class EditableInfoModal extends Component {
Who can view this information?
</div>
<Select
className={`${styles.visibility} ${darkMode ? styles.darkMode: ''}`}
options={options}
onChange={this.handleSelectChange}
value={options.find(option => option.value === this.state.visibility)}
Expand Down Expand Up @@ -367,6 +371,7 @@ EditableInfoModal.propTypes = {
areaName: PropTypes.string,
fontSize: PropTypes.number,
isPermissionPage: PropTypes.bool,
initialInfo: PropTypes.string,
darkMode: PropTypes.bool,
};

Expand All @@ -388,7 +393,7 @@ const mapStateToProps = ({ infoCollections }) => ({
});

const mapDispatchToProps = dispatch => ({
getInfoCollections: () => dispatch(getInfoCollections()),
getInfoCollections: retrieveInfos => dispatch(getInfoCollections(retrieveInfos)),
updateInfoCollection: (infoId, updatedInfo) => dispatch(updateInfoCollection(infoId, updatedInfo)),
addInfoCollection: newInfo => dispatch(addInfoCollection(newInfo)),
deleteInfoCollectionById: infoId => dispatch(deleteInfoCollectionById(infoId)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,12 @@
color: #fff !important;
}

.infoIcon {
cursor: pointer;
color: #0CF;
margin-right: 8px;
}

.visibility.darkMode > * {
background-color: #1b2a41;
}
16 changes: 14 additions & 2 deletions src/components/Warnings/Warnings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import moment from 'moment';
import PropTypes from 'prop-types';
import { useEffect, useState } from 'react';
import { Alert, Button } from 'react-bootstrap';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { toast } from 'react-toastify';
import hasPermission from '~/utils/permissions';
import { ENDPOINTS } from '~/utils/URL';
Expand All @@ -18,6 +18,7 @@ import WarningTrackerModal from './modals/WarningTrackerModal';
import WarningIcons from './WarningIcons';
import styles from './Warnings.module.css';
import { permissions } from '../../utils/constants';
import EditableInfoModal from '~/components/UserProfile/EditableModal/EditableInfoModal';
// Better Descriptions (“i” = ,ltd = Please be more specific in your time log descriptions.)
// Log Time to Tasks (“i” = ,lttt = Please log all time working on specific tasks to those tasks rather than the general category. )
// Log Time as You Go (“i” = ,ltayg = Reminder to please log your time as you go. At a minimum, please log daily any time you work.)
Expand All @@ -33,6 +34,7 @@ export default function Warning({
}) {
const dispatch = useDispatch();
const [usersWarnings, setUsersWarnings] = useState([]);
const darkMode = useSelector(state => state.theme.darkMode);

const [toggleWarningTrackerModal, setToggleWarningTrackerModal] = useState(false);
const [toggle, setToggle] = useState(false);
Expand Down Expand Up @@ -179,7 +181,17 @@ export default function Warning({
? usersWarnings.map(warning => (
<div className={`${styles['warning-item-container']}`} key={warning.title}>
<div className={`${styles['warning-wrapper']}`}>
<p className={`${styles['warning-text']}`}> {warning.title}</p>
<div className={styles.trackerInfoIcons}>
<p className={`${styles['warning-text']}`}> {warning.title}</p>
<EditableInfoModal

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each EditableInfoModal calls getInfoCollections() when it mounts, so placing it inside this map fetches the entire shared collection once per tracker. My fixture produced 8 identical requests for 8 rows. Could we fetch once above the map, guard the Redux fetch when data is already loaded, or mount/fetch the modal only when its info button is opened?

role={userRole}
areaName={`${warning?.title}Info`}
areaTitle={`${warning?.title} Tracker`}
fontSize={20}
initialInfo={warning?.description}
darkMode={darkMode}
/>
</div>
<WarningIcons
warnings={warning.warnings}
warningText={warning.title}
Expand Down
10 changes: 10 additions & 0 deletions src/components/Warnings/Warnings.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
margin: 0 auto;
}

.trackerInfoIcons {
display: flex;
gap: 5px;
align-items: center;
}

.warning-icon {
display: flex;
justify-content: flex-start;
Expand Down Expand Up @@ -103,6 +109,10 @@
box-shadow: rgb(0 0 0 / 80%) 0 0 0;
}

.warnings__descriptions.darkMode {
background: none;
}

.warning__descriptions__btn {
padding: 0 !important;
font-size: 1rem;
Expand Down
Loading
Loading