Passed
Push — task/activity-feed-applicants-... ( 843243 )
by Yonathan
05:00
created

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

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 189
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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