-
Notifications
You must be signed in to change notification settings - Fork 4
/
AnnouncementForm.tsx
168 lines (164 loc) · 5.59 KB
/
AnnouncementForm.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import * as React from "react";
import EditableInput from "./EditableInput";
import { Button } from "library-simplified-reusable-components";
export interface AnnouncementFormProps {
content?: string;
start?: string;
finish?: string;
id?: string;
add: (announcement: any) => void;
}
export interface AnnouncementFormState {
content?: string;
start?: string;
finish?: string;
id?: string;
}
export default class AnnouncementForm extends React.Component<
AnnouncementFormProps,
AnnouncementFormState
> {
constructor(props: AnnouncementFormProps) {
super(props);
this.updateStartDate = this.updateStartDate.bind(this);
this.updateEndDate = this.updateEndDate.bind(this);
const [start, finish] = this.getDefaultDates();
this.state = {
content: this.props.content || "",
start: this.props.start || start,
finish: this.props.finish || finish,
};
}
getDefaultDates(): string[] {
// By default, the start date is today's date and the end date is two months from today.
const today = new Date();
const start = this.formatDate(today);
const finish = this.formatDate(
new Date(today.setMonth(today.getMonth() + 2))
);
return [start, finish];
}
formatDate(date: Date | string): string {
if (typeof date === "string" && date.indexOf("/") === -1) {
return date;
}
const [month, day, year] =
typeof date === "string"
? date.split("/")
: date.toLocaleDateString("en-US").split("/");
return `${year}-${month.toString().length === 1 ? "0" + month : month}-${
day.toString().length === 1 ? "0" + day : day
}`;
}
updateContent(content: string) {
this.setState({ content });
}
updateStartDate(start: string) {
this.setState({ start });
// The first time you change the start date, the end date updates to be two months later.
// Presumably, if the end date has already been changed away from the default, then it's already where
// you want it, and it would just be annoying/confusing for it to keep jumping around every time you change the start date,
if (this.state.finish === this.getDefaultDates()[1]) {
const startDate = new Date(start);
const newMonth = startDate.getMonth() + 2;
const finishDate = startDate.setMonth(newMonth);
this.setState({ finish: this.formatDate(new Date(finishDate)) });
}
}
updateEndDate(finish: string) {
this.setState({ finish });
}
add(e: Event) {
// Add the current announcement to the list of announcements in the parent component (AnnouncementsSection)
e.preventDefault();
this.props.add({
content: this.state.content,
start: this.state.start,
finish: this.state.finish,
id: this.props.id || null,
});
// Restore the form to default dates and an empty content field.
const [start, finish] = this.getDefaultDates();
this.setState({ content: "", start: start, finish: finish });
}
cancel(e: Event) {
e.preventDefault();
// If an existing announcement was being edited, just put it back into the list.
if (this.props.content) {
this.add(e);
} else {
// Blank out the content field and restore the dates to their defaults.
const [start, finish] = this.getDefaultDates();
this.setState({ content: "", start: start, finish: finish });
}
}
UNSAFE_componentWillReceiveProps(newProps: AnnouncementFormProps) {
// Switch from creating a new announcement to editing an existing one.
if (newProps.content?.length > 0) {
const { content, start, finish } = newProps;
this.setState({
content: content,
start: this.formatDate(start),
finish: this.formatDate(finish),
});
}
}
render(): JSX.Element {
// None of the fields can be blank. Content must be between 15 and 350 characters.
const wrongLength =
this.state.content.length < 15 || this.state.content.length >= 350;
const shouldDisable = () => {
if (!this.state.content || !this.state.start || !this.state.finish) {
return true;
} else if (wrongLength) {
return true;
}
return false;
};
return (
<div className="announcement-form">
<EditableInput
className={wrongLength && "wrong-length"}
elementType="textarea"
type="text"
minLength={15}
maxLength={350}
value={this.state.content}
label="New Announcement Text (15-350 characters)"
optionalText={false}
onChange={(e) => this.updateContent(e)}
description={`(Current length: ${this.state.content.length}/350)`}
/>
<EditableInput
type="date"
max={this.state.finish}
value={this.state.start}
label="Start Date"
optionalText={true}
onChange={(e) => this.updateStartDate(e)}
description="If no start date is chosen, the default start date is today's date."
/>
<EditableInput
type="date"
min={this.state.start}
value={this.state.finish}
label="End Date"
optionalText={true}
onChange={(e) => this.updateEndDate(e)}
description="If no expiration date is chosen, the default expiration date is 2 months from the start date."
/>
<Button
callback={(e: Event) => this.add(e)}
content="Add"
className="inline left-align"
disabled={shouldDisable()}
/>
<Button
callback={(e: Event) => this.cancel(e)}
content="Cancel"
className="inline left-align"
/>
</div>
);
}
}