Passed
Push — dependabot/npm_and_yarn/dev/st... ( 790070...2dbd00 )
by
unknown
17:44 queued 12:22
created

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

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 183
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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