Skip to content

Commit

Permalink
fix,chore(frontend): make userDetails object property access optional…
Browse files Browse the repository at this point in the history
…, fix more tests
  • Loading branch information
JoltCode committed Dec 24, 2024
1 parent 7a91f29 commit da2927c
Show file tree
Hide file tree
Showing 42 changed files with 216 additions and 130 deletions.
2 changes: 1 addition & 1 deletion frontend/src/components/banner/topBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function TopBanner() {
(async () => {
if (data?.message) {
const html = await htmlFromMarkdown(data.message);
setSafeHTML(html.__html);
setSafeHTML(html);
}
})();
}, [data?.message])
Expand Down
11 changes: 10 additions & 1 deletion frontend/src/components/comments/commentInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ function CommentInputField({
...DROPZONE_SETTINGS,
});
const [fileuploadError, fileuploading, uploadImg] = useUploadImage();
const [commentHTML, setCommentHTML] = useState<string>();

const tribute = new Tribute({
trigger: '@',
Expand Down Expand Up @@ -96,6 +97,12 @@ function CommentInputField({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [textareaRef.current, contributors]);

useEffect(() => {
(async () => {
setCommentHTML(await htmlFromMarkdown(formatUserNamesToLink(comment)));
})();
}, [commentHTML, comment]);

const handleImagePick = async (event) =>
await uploadImg(event.target.files[0], appendImgToComment, token);

Expand Down Expand Up @@ -165,7 +172,9 @@ function CommentInputField({
<div
style={{ wordWrap: 'break-word' }}
className="blue-grey f5 lh-title markdown-content"
dangerouslySetInnerHTML={htmlFromMarkdown(formatUserNamesToLink(comment))}
dangerouslySetInnerHTML={{
__html: commentHTML,
}}
/>
)}
{!comment && (
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/formInputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ export const OrganisationSelect = ({
const [organisations, setOrganisations] = useState([]);

useEffect(() => {
if (token && userDetails && userDetails.id) {
const query = userDetails.role === 'ADMIN' ? '' : `&manager_user_id=${userDetails.id}`;
if (token && userDetails && userDetails?.id) {
const query = userDetails?.role === 'ADMIN' ? '' : `&manager_user_id=${userDetails?.id}`;
fetchLocalJSONAPI(`organisations/?omitManagerList=true${query}`, token)
.then((result) => setOrganisations(result.organisations))
.catch((e) => console.log(e));
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const Header = () => {
console.log("USERDETAILS", userDetails);

const checkUserEmail = () =>
userDetails?.hasOwnProperty('emailAddress') && !userDetails.emailAddress ? (
userDetails?.hasOwnProperty('emailAddress') && !userDetails?.emailAddress ? (
<Popup modal open closeOnEscape={false} closeOnDocumentClick={false}>
{(close) => <UpdateEmail closeModal={close} />}
</Popup>
Expand Down Expand Up @@ -191,7 +191,7 @@ export function getMenuItemsForUser(userDetails: any, organisations?: any) {
if (userDetails?.username) {
filteredMenuItems = menuItems.filter((item) => item.authenticated === true || item.showAlways);
if (
userDetails.role !== 'ADMIN' &&
userDetails?.role !== 'ADMIN' &&
(organisations === undefined || organisations.length === 0)
) {
filteredMenuItems = filteredMenuItems.filter((item) => !item.manager);
Expand Down Expand Up @@ -281,8 +281,8 @@ export const ActionItems = ({
<Dropdown
onChange={onUserMenuSelect}
value={[]}
display={<UserDisplay username={userDetails.username} />}
options={getUserLinks(userDetails.role)}
display={<UserDisplay username={userDetails?.username} />}
options={getUserLinks(userDetails?.role)}
className="blue-dark bg-white v-mid bn dn-sm"
/>
</>
Expand Down
24 changes: 18 additions & 6 deletions frontend/src/components/notifications/notificationBodyCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { fetchLocalJSONAPI } from '../../network/genericJSONRequest';
import { DeleteButton } from '../teamsAndOrgs/management';
import { ORG_NAME } from '../../config';
import './styles.scss';
import { useState } from 'react';

export const NotificationBodyModal = (props) => {
const [thisNotificationError, thisNotificationLoading, thisNotification] = useFetch(
Expand Down Expand Up @@ -92,16 +93,18 @@ export function NotificationBodyCard({
const { value, unit } = selectUnit(new Date((sentDate && new Date(sentDate)) || new Date()));
const showASendingUser =
fromUsername || (typesThatUseSystemAvatar.indexOf(messageType) !== -1 && ORG_NAME);
const [replacedSubjectHTML, setReplacedSubjectHTML] = useState('');
const [replacedMessageHTML, setReplacedMessageHTML] = useState("");

let replacedSubject;
let replacedMessage;
const [replacedSubject, setReplacedSubject] = useState('');
const [replacedMessage, setReplacedMessage] = useState('');

if (subject !== undefined) {
replacedSubject = subject.replace('task=', 'search=');
setReplacedSubject(subject.replace('task=', 'search='));
}

if (message !== undefined) {
replacedMessage = message.replace('task=', 'search=');
setReplacedMessage(message.replace('task=', 'search='));;
}
const deleteNotification = (id) => {
fetchLocalJSONAPI(`notifications/${id}/`, token, 'DELETE')
Expand All @@ -114,6 +117,11 @@ export function NotificationBodyCard({
});
};

useEffect(() => {
setReplacedSubjectHTML(rawHtmlNotification(replacedSubject).__html);
setReplacedMessageHTML(rawHtmlNotification(replacedMessage).__html);
}, [messageId, token, replacedSubject, replacedMessage]);

return (
<ReactPlaceholder ready={!loading} type="media" rows={6}>
<article className={`db base-font mb3 mh2 blue-dark mw8`}>
Expand All @@ -135,11 +143,15 @@ export function NotificationBodyCard({
<div className="pv3 pr3 pl5">
<strong
className={`pv3 messageSubjectLinks bodyCard`}
dangerouslySetInnerHTML={rawHtmlNotification(replacedSubject)}
dangerouslySetInnerHTML={{
__html: replacedSubjectHTML
}}
></strong>
<div
className={`pv3 f6 lh-title messageBodyLinks bodyCard`}
dangerouslySetInnerHTML={rawHtmlNotification(replacedMessage)}
dangerouslySetInnerHTML={{
__html: replacedMessageHTML
}}
/>
</div>
<DeleteButton
Expand Down
23 changes: 19 additions & 4 deletions frontend/src/components/notifications/notificationCard.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef } from 'react';
import { useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Popup from 'reactjs-popup';
import { Tooltip } from 'react-tooltip';
Expand All @@ -14,6 +14,7 @@ import { DeleteButton } from '../teamsAndOrgs/management';
import { RelativeTimeWithUnit } from '../../utils/formattedRelativeTime';
import { fetchLocalJSONAPI } from '../../network/genericJSONRequest';
import { NotificationBodyModal } from './notificationBodyCard';
import { useState } from 'react';

import 'reactjs-popup/dist/index.css';

Expand Down Expand Up @@ -72,7 +73,12 @@ export function NotificationCard({
const dispatch = useDispatch();
const token = useSelector((state) => state.auth.token);
const ref = useRef();
const replacedSubject = subject.replace('task=', 'search=');
const [replacedSubjectHTML, setReplacedSubjectHTML] = useState('');

useEffect(() => {
const replacedSubject = subject.replace('task=', 'search=');
setReplacedSubjectHTML(rawHtmlNotification(replacedSubject).__html);
}, [subject]);

const setMessageAsRead = () => {
!read &&
Expand Down Expand Up @@ -133,7 +139,9 @@ export function NotificationCard({
}
}}
className={`messageSubjectLinks ma0 f6`}
dangerouslySetInnerHTML={rawHtmlNotification(replacedSubject)}
dangerouslySetInnerHTML={{
__html: replacedSubjectHTML
}}
/>
<div className={`pt2 blue-grey f6`}>
<RelativeTimeWithUnit date={sentDate} />
Expand Down Expand Up @@ -203,6 +211,11 @@ export function NotificationCardMini({
read,
}) {
const dispatch = useDispatch();
const [subjectHTML, setSubjectHTML] = useState('');

useEffect(() => {
setSubjectHTML(rawHtmlNotification(subject).__html);
}, [subject]);

const setMessageAsRead = () => {
if (!read) {
Expand Down Expand Up @@ -236,7 +249,9 @@ export function NotificationCardMini({
<div
className="f7 messageSubjectLinks ws-normal"
style={{ lineHeight: 1.21 }}
dangerouslySetInnerHTML={rawHtmlNotification(subject)}
dangerouslySetInnerHTML={{
__html: subjectHTML
}}
/>
<div className="blue-grey f7 mt2">
<RelativeTimeWithUnit date={sentDate} />
Expand Down
28 changes: 22 additions & 6 deletions frontend/src/components/projectDetail/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,14 @@ export const ProjectDetailMap = (props) => {
};

export const ProjectDetailLeft = ({ project, contributors, className, type }) => {
const htmlShortDescription =
project.projectInfo && htmlFromMarkdown(project.projectInfo.shortDescription);
const [htmlShortDescriptionHTML, setHtmlShortDescriptionHTML] = useState('');

useEffect(() => {
if (!project.projectInfo) return;
(async () => {
setHtmlShortDescriptionHTML(await htmlFromMarkdown(project.projectInfo.shortDescription));
})();
}, [project.projectInfo, project.projectInfo?.shortDescription]);

return (
<div className={`${className} flex flex-column`}>
Expand All @@ -120,7 +126,9 @@ export const ProjectDetailLeft = ({ project, contributors, className, type }) =>
<section className="lh-title h5 overflow-y-auto mt3 mb3" style={{ flexGrow: 1 }}>
<div
className="pr2 blue-dark-abbey markdown-content"
dangerouslySetInnerHTML={htmlShortDescription}
dangerouslySetInnerHTML={{
__html: htmlShortDescriptionHTML
}}
/>
<div>
<a href="#description" className="link base-font bg-white f6 bn pn red pointer">
Expand Down Expand Up @@ -151,11 +159,17 @@ export const ProjectDetail = (props) => {
const { data: timelineData, status: timelineDataStatus } = useProjectTimelineQuery(
props.project.projectId,
);
const [htmlDescriptionHTML, setHtmlDescriptionHTML] = useState('');

const hasLiveMonitoringFeature = useHasLiveMonitoringFeature();

const htmlDescription =
props.project.projectInfo && htmlFromMarkdown(props.project.projectInfo.description);
useEffect(() => {
if (!props.project.projectInfo) return;
(async () => {
setHtmlDescriptionHTML(await htmlFromMarkdown(props.project.projectInfo.description));
})();
}, [props.project.projectInfo, props.project.projectInfo?.description]);

const h2Classes = 'pl4 f3 f2-ns fw5 mt2 mb3 mb4-ns ttu barlow-condensed blue-dark';
const userLink = (
<Link to={`/users/${props.project.author}`} className="link blue-dark underline">
Expand Down Expand Up @@ -185,7 +199,9 @@ export const ProjectDetail = (props) => {
</h3>
<div
className="ph4 w-60-l w-80-m w-100 lh-title markdown-content blue-dark-abbey"
dangerouslySetInnerHTML={htmlDescription}
dangerouslySetInnerHTML={{
__html: htmlDescriptionHTML
}}
/>
<a
href={`/projects/${projectId}/instructions`}
Expand Down
21 changes: 17 additions & 4 deletions frontend/src/components/projectDetail/questionsAndComments.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { lazy, Suspense, useState } from 'react';
import { lazy, Suspense, useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { useMutation } from '@tanstack/react-query';
Expand Down Expand Up @@ -143,11 +143,22 @@ export const QuestionsAndComments = ({ project, contributors, titleClass }) => {
};

export function CommentList({ userCanEditProject, projectId, comments, retryFn }) {
const username = useSelector((state) => state.auth.userDetails.username);
const username = useSelector((state) => state.auth.userDetails?.username);
const [commentsMessageHTML, setCommentsMessageHTML] = useState([]);

useEffect(() => {
if (!comments) return;
(async () => {
for (const comment of comments) {
const html = await htmlFromMarkdown(formatUserNamesToLink(comment.message));
setCommentsMessageHTML((prev) => [...prev, html]);
}
})();
}, [comments]);

return (
<div className="pt3">
{comments.map((comment) => (
{comments.map((comment, index) => (
<div
className="w-100 center cf mb2 ba0 br1 b--grey-light bg-white shadow-7 comment-item"
key={comment.id}
Expand Down Expand Up @@ -189,7 +200,9 @@ export function CommentList({ userCanEditProject, projectId, comments, retryFn }
<div
style={{ wordWrap: 'break-word' }}
className="blue-dark f5 lh-title markdown-content text-dim"
dangerouslySetInnerHTML={htmlFromMarkdown(formatUserNamesToLink(comment.message))}
dangerouslySetInnerHTML={{
__html: commentsMessageHTML[index]
}}
/>
</div>
))}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/projectEdit/metadataForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export const MetadataForm = () => {
const [campaigns, setCampaigns] = useState([]);

useEffect(() => {
if (userDetails && userDetails.id) {
const query = userDetails.role === 'ADMIN' ? '' : `&manager_user_id=${userDetails.id}`;
if (userDetails && userDetails?.id) {
const query = userDetails?.role === 'ADMIN' ? '' : `&manager_user_id=${userDetails?.id}`;
fetchLocalJSONAPI(`organisations/?omitManagerList=true${query}`, token)
.then((result) => setOrganisations(result.organisations))
.catch((e) => console.log(e));
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/projectEdit/partnersForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const PartnersForm = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dateRange]);

const { isPending, isError, data: partners } = useAllPartnersQuery(token, userDetails.id);
const { isPending, isError, data: partners } = useAllPartnersQuery(token, userDetails?.id);

const savePartnerMutation = useMutation({
mutationFn: () => {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/projects/myProjectNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const MyProjectNav = (props) => {
<FormattedMessage {...messages.myProjects} />
)}
</h3>
{(userDetails.role === 'ADMIN' || isOrgManager) && (
{(userDetails?.role === 'ADMIN' || isOrgManager) && (
<Link to={'/manage/projects/new/'} className="dib ml3">
<AddButton />
</Link>
Expand Down Expand Up @@ -176,7 +176,7 @@ export const MyProjectNav = (props) => {
</FilterButton>
</>
)}
{props.management && (userDetails.role === 'ADMIN' || isOrgManager) && (
{props.management && (userDetails?.role === 'ADMIN' || isOrgManager) && (
<>
<div className="dib pr4">
{projectStatusMenus.map((menu) => (
Expand Down Expand Up @@ -240,9 +240,9 @@ function ManagerFilters({ query, setQuery }) {
const [campaignsError, campaignsLoading, campaigns] = useFetch('campaigns/');
const [orgsError, orgsLoading, organisations] = useFetch(
`organisations/?omitManagerList=true${
userDetails.role === 'ADMIN' ? '' : `&manager_user_id=${userDetails.id}`
userDetails?.role === 'ADMIN' ? '' : `&manager_user_id=${userDetails?.id}`
}`,
userDetails && userDetails.id,
userDetails && userDetails?.id,
);
const { campaign: campaignInQuery, organisation: orgInQuery } = query;
return (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/projects/partnersFilterSelect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const PartnersFilterSelect = ({
});
const userDetails = useSelector((state) => state.auth.userDetails);
const token = useSelector((state) => state.auth.token);
const { isPending, isError, data: partners } = useAllPartnersQuery(token, userDetails.id);
const { isPending, isError, data: partners } = useAllPartnersQuery(token, userDetails?.id);

useEffect(() => {
if (queryParams.partnerId && partners) {
Expand Down
Loading

0 comments on commit da2927c

Please sign in to comment.