Skip to content

Commit 4e32e51

Browse files
committed
wip
1 parent 5452ae3 commit 4e32e51

File tree

5 files changed

+135
-26
lines changed

5 files changed

+135
-26
lines changed
Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
1-
import React, { Component } from "react";
1+
import React from "react";
22

33
import TextInput from "./TextInput";
44

55
import "./index.scss";
66

7-
class Identifier extends Component {
8-
render() {
9-
return (
10-
<div className="identifier">
11-
<TextInput
12-
label={this.props.nameLabel}
13-
value={this.props.name}
14-
onChange={this.props.nameOnChange}
15-
data-test={this.props.commentId || "nameinput"}
16-
disabled={this.props.disabled}
17-
/>
7+
const Identifier = (props) => {
8+
return (
9+
<div className="identifier">
10+
<TextInput
11+
label={props.nameLabel}
12+
value={props.name}
13+
onChange={props.nameOnChange}
14+
data-test={props.commentId || "nameinput"}
15+
disabled={props.disabled}
16+
/>
1817

19-
<TextInput
20-
label={this.props.commentLabel}
21-
value={this.props.comment}
22-
onChange={this.props.commentOnChange}
23-
multiline={true}
24-
data-test={this.props.commentId || "commentinput"}
25-
disabled={this.props.disabled}
26-
/>
27-
</div>
28-
);
29-
}
30-
}
18+
<TextInput
19+
label={props.commentLabel}
20+
value={props.comment}
21+
onChange={props.commentOnChange}
22+
multiline={true}
23+
data-test={props.commentId || "commentinput"}
24+
disabled={props.disabled}
25+
/>
26+
</div>
27+
);
28+
};
3129

3230
export default Identifier;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from "react";
2+
import { Link } from "react-router-dom";
3+
4+
import DatasetLinkedIcon from "@mui/icons-material/DatasetLinked";
5+
import { Avatar, ListItem, ListItemAvatar, Typography } from "@mui/material";
6+
7+
const displayLinks = (links) => {
8+
return links.map((link, idx) => (
9+
<Typography variant="body2" mt={2} key={`${link}-${idx}`}>
10+
<Link to={`${link}`} key={`${link}-${idx}`}>
11+
{link}
12+
</Link>
13+
</Typography>
14+
));
15+
};
16+
17+
const LinkItems = ({ projectComment }) => {
18+
const regex = /(?<=\s)\/projects[^\s,\.]*/g;
19+
const matches = projectComment.match(regex);
20+
21+
return matches && matches.length > 0 ? (
22+
<ListItem>
23+
<ListItemAvatar>
24+
<Avatar>
25+
<DatasetLinkedIcon />
26+
</Avatar>
27+
</ListItemAvatar>
28+
<>{displayLinks(matches)}</>
29+
</ListItem>
30+
) : null;
31+
};
32+
33+
export default LinkItems;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { useState } from "react";
2+
3+
import { Link, TextField, Typography } from "@mui/material";
4+
5+
const TextWithLinks = ({
6+
label,
7+
helperText,
8+
value,
9+
onChange,
10+
onBlur,
11+
onFocus,
12+
pattern,
13+
multiline = false,
14+
disabled = false,
15+
id,
16+
// eslint-disable-next-line no-useless-computed-key
17+
["data-test"]: dataTest
18+
}) => {
19+
const [inputValue, setInputValue] = useState("");
20+
const [url, setUrl] = useState("");
21+
22+
const handleInputChange = (event) => {
23+
const value = event.target.value;
24+
setInputValue(value);
25+
26+
// Simple URL detection, could use a more robust regex for URL validation
27+
const urlPattern = /https?:\/\/[^\s$.?#].[^\s]*/gi;
28+
const detectedUrl = value.match(urlPattern);
29+
setUrl(detectedUrl ? detectedUrl[0] : "");
30+
};
31+
32+
return (
33+
<>
34+
{/* TextField for input */}
35+
<TextField
36+
variant="standard"
37+
label={label}
38+
onFocus={onFocus}
39+
helperText={helperText}
40+
multiline={multiline}
41+
className="text-field"
42+
disabled={disabled}
43+
value={inputValue}
44+
id={id}
45+
// onChange={(event) => onChange(event.target.value)}
46+
onBlur={onBlur}
47+
pattern={pattern}
48+
data-test={dataTest}
49+
onChange={handleInputChange}
50+
/>
51+
52+
{/* Conditionally render the clickable URL below the TextField */}
53+
{url && (
54+
<Typography variant="body2" mt={2}>
55+
Clickable URL:{" "}
56+
<Link href={url} target="_blank" rel="noopener noreferrer">
57+
{url}
58+
</Link>
59+
</Typography>
60+
)}
61+
</>
62+
);
63+
};
64+
65+
export default TextWithLinks;

frontend/src/pages/SubProjects/ProjectDetails.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,16 @@ import {
3535
import strings from "../../localizeStrings";
3636
import ProjectAnalyticsDialog from "../Analytics/ProjectAnalyticsDialog";
3737
import BudgetEmptyState from "../Common/BudgetEmptyState";
38+
import LinkItems from "../Common/LinkItems.js";
3839

3940
import ProjectAssigneeContainer from "./ProjectAssigneeContainer";
4041

4142
import "./ProjectDetails.scss";
4243

4344
const displayTags = (tags) => {
44-
return tags.map((tag, i) => (
45+
return tags.map((tag, idx) => (
4546
<Chip
46-
key={`${tag}-${i}`}
47+
key={`${tag}-${idx}`}
4748
label={`#${formattedTag(tag)}`}
4849
style={{ margin: "1px" }}
4950
clickable={false}
@@ -77,6 +78,7 @@ const ProjectDetails = (props) => {
7778
const hasOpenSubprojects = !_isEmpty(subProjects.find((subproject) => subproject.data.status === "open"));
7879
const closeDisabled = !canClose || hasOpenSubprojects || projectStatus === "closed";
7980
const tags = displayTags(projectTags || []);
81+
8082
return (
8183
<div className="project-details-container">
8284
<Card className="project-details-card">
@@ -107,6 +109,7 @@ const ProjectDetails = (props) => {
107109
<ListItemText primary={tags} />
108110
</ListItem>
109111
) : null}
112+
<LinkItems projectComment={projectComment} />
110113
</List>
111114
<div className="project-projected-budget" data-test="project-projected-budget">
112115
<Typography variant="body1">{strings.common.total_budget}</Typography>

frontend/src/pages/SubProjects/SubProjectContainer.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ class SubProjectContainer extends Component {
7171
}
7272

7373
componentDidUpdate(prevProps) {
74+
if (this.props.router.location.pathname !== prevProps.router.location.pathname) {
75+
const newProjectId = this.props.router.location.pathname.split("/")[2];
76+
if (newProjectId !== this.projectId) {
77+
this.setState({ isDataFetched: false });
78+
this.projectId = newProjectId;
79+
this.props.setSelectedView(this.projectId, "project");
80+
this.props.fetchAllProjectDetails(this.projectId, true);
81+
this.setState({ isDataFetched: true });
82+
}
83+
}
7484
const searchTermChanges = this.props.searchTerm !== prevProps.searchTerm;
7585
const projectsChange = !_isEqual(this.props.subProjects, prevProps.subProjects);
7686

0 commit comments

Comments
 (0)