Passed
Push — feature/timeline-profile-page ( da9bea...2fc9bc )
by Tristan
04:53
created

ApplicationReviewRoot.render   A

Complexity

Conditions 1

Size

Total Lines 22
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 22
rs 9.4
c 0
b 0
f 0
cc 1
1
/* eslint camelcase: "off", @typescript-eslint/camelcase: "off" */
2
import React from "react";
3
import ReactDOM from "react-dom";
4
5
// Internationalizations
6
import { injectIntl, defineMessages, WrappedComponentProps } from "react-intl";
7
8
import camelCase from "lodash/camelCase";
9
import Swal from "sweetalert2";
10
import {
11
  Application,
12
  ReviewStatus,
13
  ApplicationReview,
14
} from "../../models/types";
15
import * as route from "../../helpers/routes";
16
import ApplicationReviewWithNav from "./ApplicationReviewWithNav";
17
import { axios } from "../../api/base";
18
import IntlContainer from "../../IntlContainer";
19
import { Portal } from "../../models/app";
20
import { ReviewStatusId } from "../../models/lookupConstants";
21
22
interface ApplicationReviewRootProps {
23
  initApplication: Application;
24
  reviewStatuses: ReviewStatus[];
25
  portal: Portal;
26
}
27
28
interface ApplicationReviewRootState {
29
  application: Application;
30
  isSaving: boolean;
31
}
32
33
interface ReviewSubmitForm {
34
  review_status_id?: number | null;
35
  notes?: string | null;
36
}
37
38
const localizations = defineMessages({
39
  oops: {
40
    id: "application.review.alert.oops",
41
    defaultMessage: "Oops...",
42
    description: "Modal notification text indicating something went wrong.",
43
  },
44
  somethingWrong: {
45
    id: "application.review.reviewSaveFailed",
46
    defaultMessage:
47
      "Something went wrong while saving a review. Try again later.",
48
    description: "Error message for error while saving an application review.",
49
  },
50
});
51
52
class ApplicationReviewRoot extends React.Component<
53
  ApplicationReviewRootProps & WrappedComponentProps,
54
  ApplicationReviewRootState
55
> {
56
  public constructor(
57
    props: ApplicationReviewRootProps & WrappedComponentProps,
58
  ) {
59
    super(props);
60
    this.state = {
61
      application: props.initApplication,
62
      isSaving: false,
63
    };
64
    this.submitReview = this.submitReview.bind(this);
65
    this.handleStatusChange = this.handleStatusChange.bind(this);
66
    this.handleNotesChange = this.handleNotesChange.bind(this);
67
    this.updateReviewState = this.updateReviewState.bind(this);
68
  }
69
70
  protected updateReviewState(review: ApplicationReview): void {
71
    const { application } = this.state;
72
    const updatedApplication = Object.assign(application, {
73
      application_review: review,
74
    });
75
    this.setState({
76
      application: updatedApplication,
77
    });
78
  }
79
80
  protected submitReview(review: ReviewSubmitForm): Promise<void> {
81
    const { application } = this.state;
82
    const { intl } = this.props;
83
84
    this.setState({ isSaving: true });
85
86
    return axios
87
      .put(route.applicationReviewUpdate(intl.locale, application.id), review)
88
      .then((response) => {
89
        const newReview = response.data as ApplicationReview;
90
        this.updateReviewState(newReview);
91
        this.setState({ isSaving: false });
92
      })
93
      .catch(() => {
94
        this.setState({ isSaving: false });
95
        Swal.fire({
96
          icon: "error",
97
          title: intl.formatMessage(localizations.oops),
98
          text: intl.formatMessage(localizations.somethingWrong),
99
        });
100
      });
101
  }
102
103
  protected handleStatusChange(
104
    applicationId: number,
105
    statusId: number | null,
106
  ): Promise<void> {
107
    const { application } = this.state;
108
    const oldReview = application.application_review
109
      ? application.application_review
110
      : {};
111
    const submitReview = Object.assign(oldReview, {
112
      review_status_id: statusId,
113
    });
114
    return this.submitReview(submitReview);
115
  }
116
117
  protected handleNotesChange(
118
    applicationId: number,
119
    notes: string | null,
120
  ): void {
121
    const { application } = this.state;
122
    const oldReview = application.application_review
123
      ? application.application_review
124
      : {};
125
    const submitReview = Object.assign(oldReview, {
126
      notes,
127
    });
128
    this.submitReview(submitReview);
129
  }
130
131
  public render(): React.ReactElement {
132
    const { reviewStatuses, portal } = this.props;
133
    const { application, isSaving } = this.state;
134
    const reviewStatusOptions = reviewStatuses
135
      .filter((status) => status.id in ReviewStatusId)
136
      .map((status) => ({
137
        value: status.id,
138
        label: camelCase(status.name),
139
      }));
140
    return (
141
      <div className="applicant-review container--layout-xl">
142
        <ApplicationReviewWithNav
143
          key={application.id}
144
          application={application}
145
          reviewStatusOptions={reviewStatusOptions}
146
          onStatusChange={this.handleStatusChange}
147
          onNotesChange={this.handleNotesChange}
148
          isSaving={isSaving}
149
          portal={portal}
150
        />
151
      </div>
152
    );
153
  }
154
}
155
156
const renderApplicationReviewRoot = (
157
  container: HTMLElement,
158
  portal: Portal,
159
) => {
160
  if (
161
    container.hasAttribute("data-application") &&
162
    container.hasAttribute("data-review-statuses")
163
  ) {
164
    const application = JSON.parse(
165
      container.getAttribute("data-application") as string,
166
    );
167
    const reviewStatuses = JSON.parse(
168
      container.getAttribute("data-review-statuses") as string,
169
    );
170
    const language = container.getAttribute("data-locale") as string;
171
    const IntlApplicationReviewRoot = injectIntl(ApplicationReviewRoot);
172
    ReactDOM.render(
173
      <IntlContainer locale={language}>
174
        <IntlApplicationReviewRoot
175
          initApplication={application}
176
          reviewStatuses={reviewStatuses}
177
          portal={portal}
178
        />
179
      </IntlContainer>,
180
      container,
181
    );
182
  }
183
};
184
185
const managerContainer = document.getElementById(
186
  "application-review-container",
187
);
188
if (managerContainer !== null) {
189
  renderApplicationReviewRoot(managerContainer, "manager");
190
}
191
192
const hrContainer = document.getElementById("application-review-container-hr");
193
if (hrContainer !== null) {
194
  renderApplicationReviewRoot(hrContainer, "hr");
195
}
196
197
export default injectIntl(ApplicationReviewRoot);
198