Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit d3e46f8

Browse files
Merge pull request #130 from topcoder-platform/dev
[PROD] Post Release Patch 1.5.2
2 parents d44d989 + 2c2cd29 commit d3e46f8

File tree

31 files changed

+423
-225
lines changed

31 files changed

+423
-225
lines changed

config/dev.js

-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ module.exports = {
99
*/
1010
CONNECT_WEBSITE_URL: "https://connect.topcoder-dev.com",
1111

12-
/**
13-
* Email to request extension
14-
*/
15-
EMAIL_REQUEST_EXTENSION: "[email protected]",
16-
1712
API: {
1813
V5: "https://api.topcoder-dev.com/v5",
1914
V3: "https://api.topcoder-dev.com/v3",

config/prod.js

-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ module.exports = {
99
*/
1010
CONNECT_WEBSITE_URL: "https://connect.topcoder.com",
1111

12-
/**
13-
* Email to request extension
14-
*/
15-
EMAIL_REQUEST_EXTENSION: "[email protected]",
16-
1712
API: {
1813
V5: "https://api.topcoder.com/v5",
1914
V3: "https://api.topcoder.com/v3",
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Report popup actions
3+
*/
4+
import { ACTION_TYPE } from "constants";
5+
6+
/**
7+
* Action to create an email popup and open it
8+
* @param {Object} popupOptions Options to customize popup appearance and behaviour
9+
* @param {Object} data Data to send to server with email text
10+
*/
11+
export const openEmailPopup = (popupOptions, data) => ({
12+
type: ACTION_TYPE.OPEN_EMAIL_POPUP,
13+
payload: { popupOptions, data },
14+
});
15+
16+
/**
17+
* Action to close an email popup
18+
*/
19+
export const closeEmailPopup = () => ({
20+
type: ACTION_TYPE.CLOSE_EMAIL_POPUP,
21+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Use email popup hook
3+
*/
4+
5+
import { useDispatch } from "react-redux";
6+
import { openEmailPopup } from "../actions";
7+
8+
/**
9+
* Hook to allow email popup to be opened by any other component
10+
* (as long as it is mounted somewhere in the tree)
11+
*
12+
* @returns func A wrapper around the open report dispatch
13+
*/
14+
export const useEmailPopup = () => {
15+
const dispatch = useDispatch();
16+
17+
return (popupOptions, data) => {
18+
dispatch(openEmailPopup(popupOptions, data));
19+
};
20+
};
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,51 @@
11
/**
2-
* A report popup used to report issues with teams or team members
2+
* An email popup used to format and send emails for reporting issues
3+
* and requesting extensions
34
*/
45

56
import React, { useCallback, useState } from "react";
7+
import _ from "lodash";
68
import { useSelector, useDispatch } from "react-redux";
79
import { toastr } from "react-redux-toastr";
8-
import { closeReport } from "./actions";
10+
import { closeEmailPopup } from "./actions";
911
import BaseModal from "components/BaseModal";
1012
import TextArea from "components/TextArea";
1113
import Button from "../Button";
12-
import { postReport } from "services/teams";
14+
import { postEmail } from "services/teams";
1315
import CenteredSpinner from "components/CenteredSpinner";
1416

15-
function ReportPopup() {
16-
const { isOpen, teamName, teamId, memberHandle } = useSelector(
17-
(state) => state.reportPopup
17+
function EmailPopup() {
18+
const { isOpen, popupOptions, data } = useSelector(
19+
(state) => state.emailPopup
1820
);
1921

2022
const dispatch = useDispatch();
2123
const [textVal, setTextVal] = useState("");
2224
const [isLoading, setIsLoading] = useState(false);
2325

24-
const submitReport = () => {
26+
const submitEmail = () => {
2527
setIsLoading(true);
2628

27-
postReport(teamName, teamId, textVal, memberHandle)
29+
const postData = _.merge({}, data);
30+
31+
_.set(postData, popupOptions.textDataField, textVal);
32+
33+
postEmail(postData)
2834
.then(() => {
2935
setIsLoading(false);
3036
closeModal();
31-
toastr.success("Report submitted successfully");
37+
toastr.success(popupOptions.successTitle);
3238
})
3339
.catch((err) => {
3440
setIsLoading(false);
3541

36-
toastr.error("Report failed", err.message);
42+
toastr.error(popupOptions.errorTitle, err.message);
3743
});
3844
};
3945

4046
const button = (
4147
<Button
42-
onClick={() => submitReport()}
48+
onClick={submitEmail}
4349
size="medium"
4450
isSubmit
4551
disabled={textVal.trim().length < 1 || isLoading}
@@ -49,17 +55,15 @@ function ReportPopup() {
4955
);
5056

5157
const closeModal = useCallback(() => {
52-
dispatch(closeReport());
58+
dispatch(closeEmailPopup());
5359
setTextVal("");
5460
}, [dispatch]);
5561

5662
return (
5763
<BaseModal
5864
open={isOpen}
5965
onClose={closeModal}
60-
title={`Issue Report - ${teamName}${
61-
memberHandle ? " - " + memberHandle : ""
62-
}`}
66+
title={popupOptions.title}
6367
button={button}
6468
disabled={isLoading}
6569
>
@@ -69,11 +73,11 @@ function ReportPopup() {
6973
<TextArea
7074
value={textVal}
7175
onChange={setTextVal}
72-
placeholder="Describe your issue"
76+
placeholder={popupOptions.textPlaceholder}
7377
/>
7478
)}
7579
</BaseModal>
7680
);
7781
}
7882

79-
export default ReportPopup;
83+
export default EmailPopup;

src/components/ReportPopup/reducers/index.js renamed to src/components/EmailPopup/reducers/index.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
/**
2-
* Reducer for Report popup
2+
* Reducer for Email popup
33
*/
44

55
import { ACTION_TYPE } from "constants";
66

77
const initialState = {
8-
teamName: undefined,
9-
teamId: undefined,
10-
memberHandle: undefined,
118
isOpen: false,
9+
popupOptions: {
10+
title: "",
11+
textPlaceholder: "",
12+
textDataField: "",
13+
},
14+
data: null,
1215
};
1316

1417
const reducer = (state = initialState, action) => {
1518
switch (action.type) {
16-
case ACTION_TYPE.OPEN_REPORT:
19+
case ACTION_TYPE.OPEN_EMAIL_POPUP:
1720
return {
1821
...state,
1922
...action.payload,
2023
isOpen: true,
2124
};
2225

23-
case ACTION_TYPE.CLOSE_REPORT:
26+
case ACTION_TYPE.CLOSE_EMAIL_POPUP:
2427
return {
2528
...state,
2629
isOpen: false,

src/components/FormField/index.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const FormField = ({ field }) => {
6464
<MarkdownEditor
6565
placeholder={field.placeholder}
6666
value={input?.value ?? ""}
67+
disabled={field.disabled}
6768
onChange={input.onChange}
6869
onBlur={input.onBlur}
6970
onFocus={input.onFocus}

src/components/MarkdownEditor/index.jsx

+29
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import React, { useCallback, useRef } from "react";
66
import PropTypes from "prop-types";
77
import cn from "classnames";
88
import TuiEditor from "../TuiEditor";
9+
import MarkdownEditorViewer from "../MarkdownEditorViewer";
910
import styles from "./styles.module.scss";
11+
import { DISABLED_DESCRIPTION_MESSAGE } from "constants";
1012

1113
const MarkdownEditor = (props) => {
1214
const editorElement = useRef(null);
@@ -15,6 +17,14 @@ const MarkdownEditor = (props) => {
1517
const markdown = editorElement.current.editorInst.getMarkdown();
1618
props.onChange(markdown);
1719
}, [props.onChange]);
20+
if (props.disabled) {
21+
return (
22+
<div styleName="editor-viewer">
23+
<MarkdownEditorViewer {...props} />
24+
<div styleName="message">{DISABLED_DESCRIPTION_MESSAGE}</div>
25+
</div>
26+
);
27+
}
1828

1929
return (
2030
<div className={cn(styles["editor-container"], props.className)}>
@@ -23,13 +33,32 @@ const MarkdownEditor = (props) => {
2333
ref={editorElement}
2434
onChange={onChange}
2535
initialValue={props.value}
36+
toolbarItems={[
37+
'heading',
38+
'bold',
39+
'italic',
40+
'strike',
41+
'code',
42+
'divider',
43+
'quote',
44+
'codeblock',
45+
'hr',
46+
'divider',
47+
'ul',
48+
'ol',
49+
'divider',
50+
'image',
51+
'link',
52+
]}
53+
plugins={[]}
2654
/>
2755
</div>
2856
);
2957
};
3058

3159
MarkdownEditor.propTypes = {
3260
value: PropTypes.string,
61+
disabled: PropTypes.bool,
3362
className: PropTypes.string,
3463
onChange: PropTypes.func,
3564
onFocus: PropTypes.func,

src/components/MarkdownEditor/styles.module.scss

+26-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
@import "styles/include";
22

3+
.editor-viewer {
4+
> div:first-child {
5+
border: 1px solid #aaaaab;
6+
border-radius: 4px;
7+
overflow: hidden;
8+
box-sizing: border-box;
9+
padding: 16px 25px 0px 25px;
10+
height: 280px;
11+
overflow-y: auto;
12+
}
13+
.message {
14+
@include font-roboto;
15+
16+
width: 100%;
17+
text-align: center;
18+
min-height: 40px;
19+
line-height: 20px;
20+
padding: 9px 10px;
21+
margin: 10px 0 5px;
22+
font-size: 14px;
23+
color: #ff5b52;
24+
border: 1px solid #ffd5d1;
25+
cursor: auto;
26+
outline: none;
27+
}
28+
}
329
.editor-container {
430
:global {
531
// reset style for heading list in headings selection popup
@@ -10,12 +36,6 @@
1036
}
1137
}
1238

13-
.tui-editor-contents {
14-
b {
15-
font-weight: bold;
16-
}
17-
}
18-
1939
// reset border color
2040
.tui-editor-defaultUI {
2141
border: 1px solid #aaaaab;

src/components/ReportPopup/actions/index.js

-22
This file was deleted.

src/components/ReportPopup/hooks/useReportPopup.js

-20
This file was deleted.

src/components/TCForm/utils.js

+1-21
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,9 @@
22
* TC Form utilty
33
*/
44
import _ from "lodash";
5+
import { getSelectOptionByValue } from "utils/helpers";
56
import { FORM_FIELD_TYPE } from "../../constants";
67

7-
/**
8-
* Returns the option from list of option by value
9-
*
10-
* @param {any} value value of option
11-
* @param {[{ label: string, value: any }]} selectOptions list of option
12-
*
13-
* @returns {{ label: string, value: any }} select option
14-
*/
15-
const getSelectOptionByValue = (value, selectOptions) => {
16-
const option = _.find(selectOptions, { value });
17-
18-
if (!option) {
19-
return {
20-
label: `Unsuppored value: ${value}`,
21-
value,
22-
};
23-
}
24-
25-
return option;
26-
};
27-
288
/**
299
* Extract value from field by type
3010
* @param {any} value value

0 commit comments

Comments
 (0)