Passed
Push — task/hr-job-review ( 40ed2c...671c4c )
by Yonathan
11:15 queued 12s
created

resources/assets/js/components/ActivityFeed.tsx   A

Complexity

Total Complexity 5
Complexity/F 0

Size

Lines of Code 178
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 5
eloc 138
mnd 5
bc 5
fnc 0
dl 0
loc 178
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
/* eslint-disable camelcase */
2
/* eslint-disable @typescript-eslint/camelcase */
3
import React, { useEffect, useState } from "react";
4
import { connect } from "react-redux";
5
import { FormattedMessage, useIntl } from "react-intl";
6
import Activity from "./Activity";
7
import { RootState } from "../store/store";
8
import { Comment } from "../models/types";
9
import { DispatchType } from "../configureStore";
10
import { fetchComments } from "../store/Job/jobActions";
11
import { getComments, sortComments } from "../store/Job/jobSelector";
12
import { commentTypeMessages } from "./CommentForm";
13
import { activityLocationOption } from "../models/localizedConstants";
14
import { activityLocationUrl } from "../models/jobUtil";
15
16
interface ActivityFeedProps {
17
  jobId: number;
18
  isHrAdvisor: boolean;
19
  comments: Comment[];
20
  handleFetchComments: (jobId: number) => Promise<void>;
21
  filterComments?: (comment: Comment) => boolean;
22
}
23
24
const ActivityFeed: React.FunctionComponent<ActivityFeedProps> = ({
25
  jobId,
26
  comments,
27
  handleFetchComments,
28
  isHrAdvisor,
29
}) => {
30
  const intl = useIntl();
31
  const { locale } = intl;
32
  if (locale !== "en" && locale !== "fr") {
33
    throw new Error("Unknown intl.locale");
34
  }
35
  const activities: Comment[] = [...comments];
36
  const [isActivitiesLoading, setIsActivitiesLoading] = useState(false);
37
  const [isError, setIsError] = useState(false);
38
39
  useEffect((): void => {
40
    setIsActivitiesLoading(true);
41
    handleFetchComments(jobId)
42
      .then(() => {
43
        setIsActivitiesLoading(false);
44
      })
45
      .catch(() => {
46
        setIsActivitiesLoading(false);
47
        setIsError(true);
48
      });
49
  }, [handleFetchComments, jobId]);
50
51
  const activityType = (type: number | null): string => {
52
    switch (type) {
53
      case 1:
54
        return intl.formatMessage(commentTypeMessages.question);
55
      case 2:
56
        return intl.formatMessage(commentTypeMessages.recommendation);
57
      case 3:
58
        return intl.formatMessage(commentTypeMessages.requiredAction);
59
      default:
60
        return intl.formatMessage(commentTypeMessages.comment);
61
    }
62
  };
63
64
  return (
65
    <section data-c-padding="top(1)">
66
      <h3 data-c-font-size="h3" data-c-color="stop" data-c-margin="bottom(1)">
67
        <FormattedMessage
68
          id="activityfeed.title"
69
          defaultMessage="Previous Activity"
70
          description="Title of activity feed."
71
        />
72
      </h3>
73
      {isError && (
74
        <p>
75
          <FormattedMessage
76
            id="activityfeed.error"
77
            defaultMessage="Something went wrong..."
78
            description="Error fetching activities."
79
          />
80
        </p>
81
      )}
82
      {isActivitiesLoading ? (
83
        <div
84
          data-c-container="form"
85
          data-c-padding="top(triple) bottom(triple)"
86
        >
87
          <div
88
            data-c-background="white(100)"
89
            data-c-card
90
            data-c-padding="all(double)"
91
            data-c-radius="rounded"
92
            data-c-align="base(centre)"
93
          >
94
            <p>
95
              <FormattedMessage
96
                id="activityfeed.loading"
97
                defaultMessage="Your activities are loading..."
98
                description="Message indicating that the activity feed is still being loaded."
99
              />
100
            </p>
101
          </div>
102
        </div>
103
      ) : (
104
        <>
105
          {activities && activities.length !== 0
106
            ? activities.map(
107
                ({
108
                  id,
109
                  comment,
110
                  location,
111
                  created_at,
112
                  type_id,
113
                }: Comment): React.ReactElement => (
114
                  <Activity
115
                    key={id}
116
                    name="Replace with Manager Name!" // TODO: Replace with user.name after User api is setup.
117
                    userRole="Replace with Manager Role!" // TODO: Replace with user.name after User api is setup.
118
                    comment={comment}
119
                    location={intl.formatMessage(
120
                      activityLocationOption(location),
121
                    )}
122
                    time={created_at}
123
                    type={activityType(type_id)}
124
                    link={{
125
                      url: activityLocationUrl(
126
                        isHrAdvisor,
127
                        location,
128
                        jobId,
129
                        locale,
130
                      ),
131
                      text: "",
132
                      title: "",
133
                    }}
134
                  />
135
                ),
136
              )
137
            : !isError && (
138
                <p>
139
                  <FormattedMessage
140
                    id="activityfeed.noActivities"
141
                    defaultMessage="No activities."
142
                    description="Message displayed when activities is empty."
143
                  />
144
                </p>
145
              )}
146
        </>
147
      )}
148
    </section>
149
  );
150
};
151
152
const mapStateToProps = (
153
  state: RootState,
154
  {
155
    filterComments = (): boolean => true,
156
  }: { filterComments?: (comment: Comment) => boolean },
157
): {
158
  comments: Comment[];
159
} => ({
160
  comments: sortComments(getComments(state).filter(filterComments)),
161
});
162
163
const mapDispatchToProps = (
164
  dispatch: DispatchType,
165
): {
166
  handleFetchComments: (jobId: number) => Promise<void>;
167
} => ({
168
  handleFetchComments: async (jobId: number): Promise<void> => {
169
    const result = await dispatch(fetchComments(jobId));
170
    if (!result.error) {
171
      return Promise.resolve();
172
    }
173
    return Promise.reject(result.error);
174
  },
175
});
176
177
export default connect(mapStateToProps, mapDispatchToProps)(ActivityFeed);
178