Skip to content

Commit b05ff39

Browse files
committed
Implemented create event
1 parent 84a9e59 commit b05ff39

File tree

9 files changed

+254
-2
lines changed

9 files changed

+254
-2
lines changed

demo/graph-tutorial/src/App.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import NavBar from './NavBar';
88
import ErrorMessage from './ErrorMessage';
99
import Welcome from './Welcome';
1010
import Calendar from './Calendar';
11+
import NewEvent from './NewEvent';
1112
import 'bootstrap/dist/css/bootstrap.css';
1213

1314
class App extends Component<AuthComponentProps> {
@@ -42,6 +43,12 @@ class App extends Component<AuthComponentProps> {
4243
<Calendar {...props} /> :
4344
<Redirect to="/" />
4445
} />
46+
<Route exact path="/newevent"
47+
render={(props) =>
48+
this.props.isAuthenticated ?
49+
<NewEvent {...props} /> :
50+
<Redirect to="/" />
51+
} />
4552
</Container>
4653
</div>
4754
</Router>

demo/graph-tutorial/src/Calendar.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33
import React from 'react';
4+
import { NavLink as RouterNavLink } from 'react-router-dom';
45
import { Table } from 'reactstrap';
56
import moment, { Moment } from 'moment-timezone';
67
import { findOneIana } from "windows-iana";
@@ -75,7 +76,7 @@ class Calendar extends React.Component<AuthComponentProps, CalendarState> {
7576
<div>
7677
<div className="mb-3">
7778
<h1 className="mb-3">{sunday.format('MMMM D, YYYY')} - {saturday.format('MMMM D, YYYY')}</h1>
78-
<a className="btn btn-light btn-sm" href="#">New event</a>
79+
<RouterNavLink to="/newevent" className="btn btn-light btn-sm" exact>New event</RouterNavLink>
7980
</div>
8081
<div className="calendar-week">
8182
<div className="table-responsive">

demo/graph-tutorial/src/CalendarDayRow.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export default class CalendarDayRow extends React.Component<CalendarDayRowProps>
3636
var today = moment();
3737
var rowClass = today.day() === this.props.date?.day() ? 'table-warning' : '';
3838
var timeFormat = this.props.timeFormat;
39-
console.log(timeFormat);
4039

4140
var dateCell = (
4241
<td className='calendar-view-date-cell' rowSpan={this.props.events.length <= 0 ? 1 : this.props.events.length}>

demo/graph-tutorial/src/GraphService.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export async function getUserWeekCalendar(accessToken: string, timeZone: string,
4242
var startDateTime = startDate.format();
4343
var endDateTime = moment(startDate).add(7, 'day').format();
4444

45+
// GET /me/calendarview?startDateTime=''&endDateTime=''
46+
// &$select=subject,organizer,start,end
47+
// &$orderby=start/dateTime
48+
// &$top=50
4549
var response: PageCollection = await client
4650
.api('/me/calendarview')
4751
.header("Prefer", `outlook.timezone="${timeZone}"`)
@@ -71,3 +75,16 @@ export async function getUserWeekCalendar(accessToken: string, timeZone: string,
7175

7276
}
7377
// </getUserWeekCalendarSnippet>
78+
79+
// <createEventSnippet>
80+
export async function createEvent(accessToken: string, newEvent: Event): Promise<Event> {
81+
const client = getAuthenticatedClient(accessToken);
82+
83+
// POST /me/events
84+
// JSON representation of the new event is sent in the
85+
// request body
86+
return await client
87+
.api('/me/events')
88+
.post(newEvent);
89+
}
90+
// </createEventSnippet>
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
// <NewEventSnippet>
5+
import React from 'react';
6+
import { NavLink as RouterNavLink, Redirect } from 'react-router-dom';
7+
import { Button, Col, Form, FormGroup, Label, Input, Row } from 'reactstrap';
8+
import { Attendee, Event } from 'microsoft-graph';
9+
import { config } from './Config';
10+
import withAuthProvider, { AuthComponentProps } from './AuthProvider';
11+
import { createEvent } from './GraphService';
12+
13+
interface NewEventState {
14+
subject: string;
15+
attendees: string;
16+
start: string;
17+
end: string;
18+
body: string;
19+
disableCreate: boolean;
20+
redirect: boolean;
21+
}
22+
23+
class NewEvent extends React.Component<AuthComponentProps, NewEventState> {
24+
25+
constructor(props: any) {
26+
super(props);
27+
28+
this.state = {
29+
subject: '',
30+
attendees: '',
31+
start: '',
32+
end: '',
33+
body: '',
34+
disableCreate: true,
35+
redirect: false
36+
}
37+
38+
this.handleUpdate = this.handleUpdate.bind(this);
39+
this.isFormDisabled = this.isFormDisabled.bind(this);
40+
this.createEvent = this.createEvent.bind(this);
41+
}
42+
43+
// Called whenever an input is changed
44+
handleUpdate(event: React.ChangeEvent<HTMLInputElement>) {
45+
// Set the state value that maps to the input
46+
var newState: any = {
47+
[event.target.name]: event.target.value
48+
};
49+
50+
this.setState(newState);
51+
}
52+
53+
// Determines if form is ready to submit
54+
// Requires a subject, start, and end
55+
isFormDisabled(): boolean {
56+
return this.state.subject.length === 0 ||
57+
this.state.start.length === 0 ||
58+
this.state.end.length === 0;
59+
}
60+
61+
// Creates the event when user clicks Create
62+
async createEvent() {
63+
// Get the value of attendees and split into an array
64+
var attendeeEmails = this.state.attendees.split(';');
65+
var attendees: Attendee[] = [];
66+
67+
// Create an Attendee object for each email address
68+
attendeeEmails.forEach((email) => {
69+
if (email.length > 0) {
70+
attendees.push({
71+
emailAddress: {
72+
address: email
73+
}
74+
});
75+
}
76+
});
77+
78+
// Create the Event object
79+
var newEvent: Event = {
80+
subject: this.state.subject,
81+
// Only add if there are attendees
82+
attendees: attendees.length > 0 ? attendees : undefined,
83+
// Specify the user's time zone so
84+
// the start and end are set correctly
85+
start: {
86+
dateTime: this.state.start,
87+
timeZone: this.props.user.timeZone
88+
},
89+
end: {
90+
dateTime: this.state.start,
91+
timeZone: this.props.user.timeZone
92+
},
93+
// Only add if a body was given
94+
body: this.state.body.length > 0 ? {
95+
contentType: "text",
96+
content: this.state.body
97+
} : undefined
98+
}
99+
100+
try {
101+
// Get the user's access token
102+
var accessToken = await this.props.getAccessToken(config.scopes);
103+
104+
// Create the event
105+
await createEvent(accessToken, newEvent);
106+
107+
// Redirect to the calendar view
108+
this.setState({ redirect: true });
109+
}
110+
catch (err) {
111+
this.props.setError('ERROR', JSON.stringify(err));
112+
}
113+
}
114+
115+
render() {
116+
if (this.state.redirect) {
117+
return <Redirect to="/calendar" />
118+
}
119+
120+
return (
121+
<Form>
122+
<FormGroup>
123+
<Label for="subject">Subject</Label>
124+
<Input type="text"
125+
name="subject"
126+
id="subject"
127+
value={this.state.subject}
128+
onChange={this.handleUpdate} />
129+
</FormGroup>
130+
<FormGroup>
131+
<Label for="attendees">Attendees</Label>
132+
<Input type="text"
133+
name="attendees"
134+
id="attendees"
135+
placeholder="Enter a list of email addresses, seperated by a semi-colon"
136+
value={this.state.attendees}
137+
onChange={this.handleUpdate} />
138+
</FormGroup>
139+
<Row form>
140+
<Col>
141+
<FormGroup>
142+
<Label for="start">Start</Label>
143+
<Input type="datetime-local"
144+
name="start"
145+
id="start"
146+
value={this.state.start}
147+
onChange={this.handleUpdate} />
148+
</FormGroup>
149+
</Col>
150+
<Col>
151+
<FormGroup>
152+
<Label for="end">End</Label>
153+
<Input type="datetime-local"
154+
name="end"
155+
id="end"
156+
value={this.state.end}
157+
onChange={this.handleUpdate} />
158+
</FormGroup>
159+
</Col>
160+
</Row>
161+
<FormGroup>
162+
<Label for="body">Body</Label>
163+
<Input type="textarea"
164+
name="body"
165+
id="body"
166+
value={this.state.body}
167+
onChange={this.handleUpdate} />
168+
</FormGroup>
169+
<Button color="primary"
170+
className="mr-2"
171+
disabled={this.isFormDisabled()}
172+
onClick={this.createEvent}>Create</Button>
173+
<RouterNavLink to="/calendar" className="btn btn-secondary" exact>Cancel</RouterNavLink>
174+
</Form>
175+
)
176+
}
177+
}
178+
179+
export default withAuthProvider(NewEvent);
180+
// </NewEventSnippet>

tutorial/05-add-ms-graph.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ In this exercise you will incorporate the Microsoft Graph into the application.
2222

2323
```typescript
2424
import React from 'react';
25+
import { NavLink as RouterNavLink } from 'react-router-dom';
2526
import { Table } from 'reactstrap';
2627
import moment from 'moment-timezone';
2728
import { findOneIana } from "windows-iana";
@@ -119,6 +120,13 @@ Now you can update the `Calendar` component to display the events in a more user
119120

120121
:::code language="typescript" source="../demo/graph-tutorial/src/CalendarDayRow.tsx" id="CalendarDayRowSnippet":::
121122

123+
1. Add the following `import` statements to the top of **Calendar.tsx**.
124+
125+
```typescript
126+
import CalendarDayRow from './CalendarDayRow';
127+
import './Calendar.css';
128+
```
129+
122130
1. Replace the existing `render` function in `./src/Calendar.tsx` with the following function.
123131

124132
:::code language="typescript" source="../demo/graph-tutorial/src/Calendar.tsx" id="renderSnippet":::

tutorial/06-create-event.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!-- markdownlint-disable MD002 MD041 -->
2+
3+
In this section you will add the ability to create events on the user's calendar.
4+
5+
## Add method to GraphService
6+
7+
1. Open **./src/GraphService.ts** and add the following function to create a new event.
8+
9+
:::code language="typescript" source="../demo/graph-tutorial/src/GraphService.ts" id="createEventSnippet":::
10+
11+
## Create new event form
12+
13+
1. Create a new file in the **./src** directory named **NewEvent.tsx** and add the following code.
14+
15+
:::code language="typescript" source="../demo/graph-tutorial/src/NewEvent.tsx" id="NewEventSnippet":::
16+
17+
1. Open **./src/App.tsx** and add the following `import` statement to the top of the file.
18+
19+
```typescript
20+
import NewEvent from './NewEvent';
21+
```
22+
23+
1. Add a new route to the new event form. Add the following code just after the other `Route` elements.
24+
25+
```typescript
26+
<Route exact path="/newevent"
27+
render={(props) =>
28+
this.props.isAuthenticated ?
29+
<NewEvent {...props} /> :
30+
<Redirect to="/" />
31+
} />
32+
```
33+
34+
The full `return` statement should now look like this.
35+
36+
:::code language="typescript" source="../demo/graph-tutorial/src/App.tsx" id="renderSnippet" highlight="23-28":::
37+
38+
1. Refresh the app and browse to the calendar view. Click the **New event** button. Fill in the fields and click **Create**.
39+
40+
![A screenshot of the new event form](./images/create-event-01.png)
File renamed without changes.
27.1 KB
Loading

0 commit comments

Comments
 (0)