Passed
Push — feature/hr-admin-panel ( f19c55...ceb1d1 )
by Grant
07:17 queued 03:01
created

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

Complexity

Total Complexity 5
Complexity/F 0

Size

Lines of Code 187
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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