Создание одностраничных приложений React с помощью Microsoft Graph
В этом руководстве рассказывается, как создать React-страницу приложения, которое использует API microsoft Graph для получения сведений о календаре для пользователя.
Совет
Если вы предпочитаете просто скачать завершенный учебник, вы можете скачать или клонировать GitHub репозиторий.
Предварительные требования
Перед началом этого руководства необходимо установитьNode.jsи пряжу на компьютере разработки. Если у вас нет Node.js или пряжи, посетите предыдущие ссылки для скачать варианты.
Вы также должны иметь личную учетную запись Майкрософт с почтовым ящиком на Outlook.com или учетную запись Microsoft work или school. Если у вас нет учетной записи Майкрософт, существует несколько вариантов получения бесплатной учетной записи:
- Вы можете зарегистрироваться на новую личную учетную запись Майкрософт.
- Вы можете зарегистрироваться в программе Microsoft 365 разработчика, чтобы получить бесплатную Microsoft 365 подписку.
Примечание
Этот учебник был написан с версией Node 14.15.0 и Yarn версии 1.22.10. Действия в этом руководстве могут работать с другими версиями, но они не были проверены.
Отзывы
Обратите внимание на этот учебник в репозитории GitHub.
Создание одностраничного приложения React
В этом разделе вы создайте новое приложение React.
Откройте интерфейс командной строки (CLI), перейдите в каталог, в котором у вас есть права на создание файлов, и запустите следующие команды для создания React приложения.
yarn create react-app graph-tutorial --template typescript
После завершения команды измените каталог график-учебник"** в CLI и запустите следующую команду, чтобы запустить локальный веб-сервер.
yarn start
Примечание
Если у вас нет установленной пряжи, вы можете использовать
npm start
вместо этого.
Браузер по умолчанию открывается https://localhost:3000/ на странице React по умолчанию. Если браузер не открыт, откройте его и просмотрите, чтобы убедиться, https://localhost:3000/ что новое приложение работает.
Добавление пакетов node
Прежде чем двигаться дальше, установите дополнительные пакеты, которые вы будете использовать позже:
- react-router-dom для декларативной маршрутизирования внутри React приложения.
- bootstrap для укладки и общих компонентов.
- react-bootstrap для React компонентов на основе Bootstrap.
- date-fns для форматирования дат и времени.
- windows-iana для перевода Windows часовых поясов в формат IANA.
- msal-react для проверки подлинности Azure Active Directory и получения маркеров доступа.
- microsoft-graph-client для звонков в Microsoft Graph.
Запустите следующую команду в CLI.
yarn add react-router-dom@5.2.0 bootstrap@5.0.1 react-bootstrap@2.0.0-beta.4 windows-iana@5.0.2
yarn add date-fns@2.22.1 date-fns-tz@1.1.4 @azure/msal-react@1.0.1 @azure/msal-browser@2.16.1 @microsoft/microsoft-graph-client@3.0.0
yarn add -D @types/react-router-dom@5.1.8 @types/microsoft-graph
Проектирование приложения
Начните с создания контекста для приложения.
Создайте новый файл в каталоге ./src с именем AppContext.tsx и добавьте следующие
import
утверждения.import React, { useContext, createContext, useState, MouseEventHandler, useEffect} from 'react'; import { AuthCodeMSALBrowserAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/authCodeMsalBrowser'; import { InteractionType, PublicClientApplication } from '@azure/msal-browser'; import { useMsal } from '@azure/msal-react';
Добавьте в него указанный ниже код.
Добавьте следующую функцию в конце ./src/AppContext.tsx.
function useProvideAppContext() { const [user, setUser] = useState<AppUser | undefined>(undefined); const [error, setError] = useState<AppError | undefined>(undefined); const displayError = (message: string, debug?: string) => { setError({message, debug}); } const clearError = () => { setError(undefined); } const authProvider = undefined; const signIn = async () => { // TODO }; const signOut = async () => { // TODO }; return { user, error, signIn, signOut, displayError, clearError, authProvider }; }
Вы завершите реализацию этого контекста в более поздних разделах.
Создайте navbar для приложения. Создайте новый файл в
./src
каталоге с именемNavBar.tsx
и добавьте следующий код.import React from 'react'; import { NavLink as RouterNavLink } from 'react-router-dom'; import { Button, Collapse, Container, Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink, UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; import '@fortawesome/fontawesome-free/css/all.css'; interface NavBarProps { isAuthenticated: boolean; authButtonMethod: any; user: any; } interface NavBarState { isOpen: boolean; } function UserAvatar(props: any) { // If a user avatar is available, return an img tag with the pic if (props.user.avatar) { return <img src={props.user.avatar} alt="user" className="rounded-circle align-self-center mr-2" style={{ width: '32px' }}></img>; } // No avatar available, return a default icon return <i className="far fa-user-circle fa-lg rounded-circle align-self-center mr-2" style={{ width: '32px' }}></i>; } function AuthNavItem(props: NavBarProps) { // If authenticated, return a dropdown with the user's info and a // sign out button if (props.isAuthenticated) { return ( <UncontrolledDropdown> <DropdownToggle nav caret> <UserAvatar user={props.user} /> </DropdownToggle> <DropdownMenu right> <h5 className="dropdown-item-text mb-0">{props.user.displayName}</h5> <p className="dropdown-item-text text-muted mb-0">{props.user.email}</p> <DropdownItem divider /> <DropdownItem onClick={props.authButtonMethod}>Sign Out</DropdownItem> </DropdownMenu> </UncontrolledDropdown> ); } // Not authenticated, return a sign in link return ( <NavItem> <Button onClick={props.authButtonMethod} className="btn-link nav-link border-0" color="link">Sign In</Button> </NavItem> ); } export default class NavBar extends React.Component<NavBarProps, NavBarState> { constructor(props: NavBarProps) { super(props); this.toggle = this.toggle.bind(this); this.state = { isOpen: false }; } toggle() { this.setState({ isOpen: !this.state.isOpen }); } render() { // Only show calendar nav item if logged in let calendarLink = null; if (this.props.isAuthenticated) { calendarLink = ( <NavItem> <RouterNavLink to="/calendar" className="nav-link" exact>Calendar</RouterNavLink> </NavItem> ); } return ( <div> <Navbar color="dark" dark expand="md" fixed="top"> <Container> <NavbarBrand href="/">React Graph Tutorial</NavbarBrand> <NavbarToggler onClick={this.toggle} /> <Collapse isOpen={this.state.isOpen} navbar> <Nav className="mr-auto" navbar> <NavItem> <RouterNavLink to="/" className="nav-link" exact>Home</RouterNavLink> </NavItem> {calendarLink} </Nav> <Nav className="justify-content-end" navbar> <NavItem> <NavLink href="https://developer.microsoft.com/graph/docs/concepts/overview" target="_blank"> <i className="fas fa-external-link-alt mr-1"></i> Docs </NavLink> </NavItem> <AuthNavItem isAuthenticated={this.props.isAuthenticated} authButtonMethod={this.props.authButtonMethod} user={this.props.user} /> </Nav> </Collapse> </Container> </Navbar> </div> ); } }
Создание домашней страницы для приложения. Создайте новый файл в
./src
каталоге с именемWelcome.tsx
и добавьте следующий код.import React from 'react'; import { Button, Jumbotron } from 'reactstrap'; interface WelcomeProps { isAuthenticated: boolean; authButtonMethod: any; user: any; } interface WelcomeState { isOpen: boolean; } function WelcomeContent(props: WelcomeProps) { // If authenticated, greet the user if (props.isAuthenticated) { return ( <div> <h4>Welcome {props.user.displayName}!</h4> <p>Use the navigation bar at the top of the page to get started.</p> </div> ); } // Not authenticated, present a sign in button return <Button color="primary" onClick={props.authButtonMethod}>Click here to sign in</Button>; } export default class Welcome extends React.Component<WelcomeProps, WelcomeState> { render() { return ( <Jumbotron> <h1>React Graph Tutorial</h1> <p className="lead"> This sample app shows how to use the Microsoft Graph API to access Outlook and OneDrive data from React </p> <WelcomeContent isAuthenticated={this.props.isAuthenticated} user={this.props.user} authButtonMethod={this.props.authButtonMethod} /> </Jumbotron> ); } }
Создайте дисплей сообщения об ошибке для отображения сообщений пользователю. Создайте новый файл в
./src
каталоге с именемErrorMessage.tsx
и добавьте следующий код.import React from 'react'; import { Alert } from 'reactstrap'; interface ErrorMessageProps { debug: string; message: string; } export default class ErrorMessage extends React.Component<ErrorMessageProps> { render() { let debug = null; if (this.props.debug) { debug = <pre className="alert-pre border bg-light p-2"><code>{this.props.debug}</code></pre>; } return ( <Alert color="danger"> <p className="mb-3">{this.props.message}</p> {debug} </Alert> ); } }
Откройте файл
./src/index.css
и замените его содержимое приведенным ниже кодом.body { padding-top: 4.5rem; } .alert-pre { word-wrap: break-word; word-break: break-all; white-space: pre-wrap; }
Откройте
./src/App.tsx
и замените все содержимое следующим.import { BrowserRouter as Router, Route } from 'react-router-dom'; import { Container } from 'react-bootstrap'; import { MsalProvider } from '@azure/msal-react' import { IPublicClientApplication } from '@azure/msal-browser'; import ProvideAppContext from './AppContext'; import ErrorMessage from './ErrorMessage'; import NavBar from './NavBar'; import Welcome from './Welcome'; import 'bootstrap/dist/css/bootstrap.css'; export default function App() { return( <ProvideAppContext> <Router> <NavBar /> <Container> <ErrorMessage /> <Route exact path="/" render={(props) => <Welcome {...props} /> } /> </Container> </Router> </ProvideAppContext> ); }
Добавьте файл изображений выбора с именем no-profile-photo.png в каталоге ./public/images. Это изображение будет использоваться в качестве фотографии пользователя, если у пользователя нет фотографии в Microsoft Graph.
Сохраните все изменения и перезапустите приложение. Теперь приложение должно выглядеть совсем по-другому.
Регистрация приложения на портале
В этом упражнении будет создаваться новая регистрация веб-приложений Azure AD с помощью центра администрирования Azure Active Directory администратора.
Откройте браузер и перейдите в Центр администрирования Azure Active Directory. Войдите с помощью личной учетной записи (т.е. учетной записи Microsoft) или рабочей (учебной) учетной записи.
Выберите Azure Active Directory на панели навигации слева, затем выберите Регистрация приложений в разделе Управление.
Примечание
Пользователи Azure AD B2C могут видеть только регистрации приложений (устаревшие). В этом случае перейдите непосредственно к https://aka.ms/appregistrations .
Выберите Новая регистрация. На странице Зарегистрировать приложение задайте необходимые значения следующим образом.
- Введите имя
React Graph Tutorial
. - Введите поддерживаемые типы учетных записей для учетных записей в любом каталоге организаций и личных учетных записей Microsoft.
- В разделе URI адрес перенаправления введите значение в первом раскрывающемся списке
Single-page application (SPA)
и задайте значениеhttp://localhost:3000
.
- Введите имя
Нажмите кнопку Зарегистрировать. На странице React Graph учебника скопируйте значение ID приложения (клиента) и сохраните его, оно потребуется на следующем шаге.
Добавление проверки подлинности с помощью Azure AD
В этом упражнении вы расширит приложение от предыдущего упражнения для поддержки проверки подлинности с помощью Azure AD. Это необходимо для получения необходимого маркера доступа OAuth для вызова microsoft Graph. На этом этапе вы интегрируете библиотеку проверки подлинности Майкрософт в приложение.
Создайте новый файл в каталоге ./src с именем Config.ts и добавьте следующий код.
export const config = { appId: 'YOUR_APP_ID_HERE', redirectUri: 'http://localhost:3000', scopes: [ 'user.read', 'mailboxsettings.read', 'calendars.readwrite' ] };
Замените
YOUR_APP_ID_HERE
с помощью ID приложения с портала регистрации приложений.Важно!
Если вы используете источник управления, например git, сейчас самое время исключить файл из источника управления, чтобы избежать случайной утечки вашего
Config.ts
ID приложения.
Реализация входа в систему
В этом разделе реализуется поставщик проверки подлинности, вход и вход.
Откройте ./src/index.tsx и добавьте следующие утверждения в
import
верхней части файла.import { PublicClientApplication, EventType, EventMessage, AuthenticationResult } from '@azure/msal-browser'; import config from './Config';
Добавьте следующий код перед
ReactDOM.render
строкой.В этом коде создается экземпляр объекта библиотеки MSAL, проверяется наличие кэшных учетных записей и регистрируется вызов для набора активной учетной записи после успешного
PublicClientApplication
входа.App
Обнови элемент вReactDOM.render
вызове, чтобы передатьmsalInstance
свойство с именемpca
.Откройте ./src/App.tsx и добавьте следующий код после последнего
import
заявления.Замените имеющуюся функцию
App
указанным ниже кодом.export default function App({ pca }: AppProps) { return( <MsalProvider instance={ pca }> <ProvideAppContext> <Router> <div> <NavBar /> <Container> <ErrorMessage /> <Route exact path="/" render={(props) => <Welcome {...props} /> } /> </Container> </div> </Router> </ProvideAppContext> </MsalProvider> ); }
Это обертывание всех остальных элементов элементом, что делает состояние проверки подлинности и приобретение
MsalProvider
маркеров доступными.Откройте ./src/AppContext.tsx и добавьте следующее утверждение в
import
верхней части файла.import config from './Config';
Добавьте следующую строку в верхней части
useProvideAppContext
функции.const msal = useMsal();
Замените
const authProvider = undefined;
строку следующей.Замените имеющуюся функцию
signIn
указанным ниже кодом.const signIn = async () => { const result = await msal.instance.loginPopup({ scopes: config.scopes, prompt: 'select_account' }); // TEMPORARY: Show the access token displayError('Access token retrieved', result.accessToken); };
Сохраните изменения и обновите браузер. Нажмите кнопку вход, и вы увидите всплывающее окно, которое загружает
https://login.microsoftonline.com
. Вход с учетной записью Майкрософт и согласие на запрашиваемую разрешения. Страница приложения должна обновиться, показывая маркер.
Получение сведений о пользователе
В этом разделе вы измените функцию, чтобы получить сведения пользователя из signIn
Microsoft Graph.
Создайте новый файл в каталоге ./src с именем GraphService.ts и добавьте следующий код.
Это реализует функцию, которая инициализирует клиент Microsoft Graph с предоставленным, и получает
getUser
AuthProvider
профиль пользователя.Откройте ./src/AppContext.tsx и добавьте следующее утверждение в
import
верхней части файла.import { getUser } from './GraphService';
Замените имеющуюся функцию
signIn
указанным ниже кодом.Замените имеющуюся функцию
signOut
указанным ниже кодом.Добавьте следующий
useEffect
вызов внутрьuseProvideAppContext
.Сохраните изменения и запустите приложение после регистрации на домашней странице, но пользовательский интерфейс должен измениться, чтобы указать, что вы подписаны.
Щелкните аватар пользователя в правом верхнем углу, чтобы получить доступ к ссылке Sign Out. Щелкнув кнопку "Выйти", вы сбросит сеанс и возвращает вас на домашнюю страницу.
Хранение и обновление маркеров
На этом этапе у приложения есть маркер доступа, который отправляется в Authorization
заголовке вызовов API. Это маркер, который позволяет приложению получать доступ к microsoft Graph от имени пользователя.
Однако этот маркер недолговечен. Срок действия маркера истекает через час после его выпуска. Вот здесь и пригодится маркер обновления. Маркер обновления позволяет приложению запрашивать новый маркер доступа, не требуя от пользователя повторного входа в систему.
Поскольку приложение использует библиотеку MSAL, не нужно внедрять логику хранения маркеров или обновления. PublicClientApplication
Кэшет маркера в сеансе браузера. Метод сначала проверяет кэш-маркер, и если срок его действия не истек, он acquireTokenSilent
возвращает его. Если срок действия истек, он использует кэшный маркер обновления для получения нового. Этот метод будет больше использовать в следующем модуле.
Просмотр календаря
В этом упражнении вы будете включать Graph Microsoft в приложение. Для этого приложения вы будете использовать библиотеку microsoft-graph-client для звонков в Microsoft Graph.
Получение событий календаря из Outlook
Откройте ./src/GraphService.ts и добавьте следующую функцию.
export async function getUserWeekCalendar(accessToken: string, timeZone: string, startDate: Moment): Promise<Event[]> { const client = getAuthenticatedClient(accessToken); // Generate startDateTime and endDateTime query params // to display a 7-day window var startDateTime = startDate.format(); var endDateTime = moment(startDate).add(7, 'day').format(); // GET /me/calendarview?startDateTime=''&endDateTime='' // &$select=subject,organizer,start,end // &$orderby=start/dateTime // &$top=50 var response: PageCollection = await client .api('/me/calendarview') .header('Prefer', `outlook.timezone="${timeZone}"`) .query({ startDateTime: startDateTime, endDateTime: endDateTime }) .select('subject,organizer,start,end') .orderby('start/dateTime') .top(25) .get(); if (response["@odata.nextLink"]) { // Presence of the nextLink property indicates more results are available // Use a page iterator to get all results var events: Event[] = []; // Must include the time zone header in page // requests too var options: GraphRequestOptions = { headers: { 'Prefer': `outlook.timezone="${timeZone}"` } }; var pageIterator = new PageIterator(client, response, (event) => { events.push(event); return true; }, options); await pageIterator.iterate(); return events; } else { return response.value; } }
Давайте посмотрим, что делает этот код.
- Вызывается URL-адрес
/me/calendarview
. - Метод
header
добавляет загонPrefer: outlook.timezone=""
в запрос, в результате чего время отклика будет в предпочтительном часовом поясе пользователя. - Метод
query
добавляет параметрыstartDateTime
endDateTime
и добавляет окно времени для представления календаря. - Метод
select
ограничивает поля, возвращенные для каждого события, только теми, которые будут фактически использовать представление. - Метод
orderby
сортировать результаты по дате и времени их создания, причем последний элемент является первым. - Метод
top
ограничивает результаты на одной странице 25 событиями. - Если в ответе содержится
@odata.nextLink
значение, указывающее на то, что доступны дополнительные результаты,PageIterator
объект используется для страницы в коллекции, чтобы получить все результаты.
- Вызывается URL-адрес
Создайте React для отображения результатов вызова. Создайте новый файл в каталоге ./src с именем Calendar.tsx и добавьте следующий код.
import { useEffect, useState } from 'react'; import { NavLink as RouterNavLink, RouteComponentProps } from 'react-router-dom'; import { Table } from 'react-bootstrap'; import { findIana } from "windows-iana"; import { Event } from 'microsoft-graph'; import { getUserWeekCalendar } from './GraphService'; import { useAppContext } from './AppContext'; import { AuthenticatedTemplate } from '@azure/msal-react'; import { add, format, getDay, parseISO } from 'date-fns'; import { endOfWeek, startOfWeek } from 'date-fns/esm'; export default function Calendar(props: RouteComponentProps) { const app = useAppContext(); const [events, setEvents] = useState<Event[]>(); useEffect(() => { const loadEvents = async() => { if (app.user && !events) { try { const ianaTimeZones = findIana(app.user?.timeZone!); const events = await getUserWeekCalendar(app.authProvider!, ianaTimeZones[0].valueOf()); setEvents(events); } catch (err) { app.displayError!(err.message); } } }; loadEvents(); }); return ( <AuthenticatedTemplate> <pre><code>{JSON.stringify(events, null, 2)}</code></pre> </AuthenticatedTemplate> ); }
Пока это только отрисовка массива событий в JSON на странице.
Добавьте этот новый компонент в приложение. Откройте
./src/App.tsx
и добавьте следующееimport
утверждение в верхней части файла.import Calendar from './Calendar';
Добавьте следующий компонент сразу после существующего
<Route>
.<Route exact path="/calendar" render={(props) => <Calendar {...props} /> } />
Сохраните изменения и перезапустите приложение. Войдите и щелкните ссылку Календарь в панели nav. Если все работает надлежащим образом, в календаре пользователя должен появиться дамп событий в формате JSON.
Отображение результатов
Теперь вы можете обновить компонент Calendar
, чтобы отображать события более удобным для пользователя образом.
Создайте новый файл в каталоге
./src
с именемCalendar.css
и добавьте следующий код..calendar-view-date-cell { width: 150px; } .calendar-view-date { width: 40px; font-size: 36px; line-height: 36px; margin-right: 10px; } .calendar-view-month { font-size: 0.75em; } .calendar-view-timespan { width: 200px; } .calendar-view-subject { font-size: 1.25em; } .calendar-view-organizer { font-size: .75em; }
Создайте компонент React для отображения событий в один день в качестве строк таблицы. Создайте новый файл в каталоге
./src
с именемCalendarDayRow.tsx
и добавьте следующий код.import React from 'react'; import moment, { Moment } from 'moment'; import { Event } from 'microsoft-graph'; interface CalendarDayRowProps { date: Moment | undefined; timeFormat: string; events: Event[]; } interface FormatMap { [key: string] : string; } // moment.js format strings are slightly // different than the ones returned by Graph const formatMap: FormatMap = { "h:mm tt": "h:mm A", "hh:mm tt": "hh:mm A" }; // Helper function to format Graph date/time in the user's // preferred format function formatDateTime(dateTime: string | undefined, format: string) { if (dateTime !== undefined) { return moment(dateTime).format(formatMap[format] || format); } } export default class CalendarDayRow extends React.Component<CalendarDayRowProps> { render() { var today = moment(); var rowClass = today.day() === this.props.date?.day() ? 'table-warning' : ''; var timeFormat = this.props.timeFormat; var dateCell = ( <td className='calendar-view-date-cell' rowSpan={this.props.events.length <= 0 ? 1 : this.props.events.length}> <div className='calendar-view-date float-left text-right'>{this.props.date?.format('DD')}</div> <div className='calendar-view-day'>{this.props.date?.format('dddd')}</div> <div className='calendar-view-month text-muted'>{this.props.date?.format('MMMM, YYYY')}</div> </td> ); if (this.props.events.length <= 0) { // Render an empty row for the day return ( <tr className={rowClass}> {dateCell} <td></td> <td></td> </tr> ); } return ( <React.Fragment> {this.props.events.map( function(event: Event, index: Number) { return ( <tr className={rowClass} key={event.id}> { index === 0 && dateCell } <td className="calendar-view-timespan"> <div>{formatDateTime(event.start?.dateTime, timeFormat)} - {formatDateTime(event.end?.dateTime, timeFormat)}</div> </td> <td> <div className="calendar-view-subject">{event.subject}</div> <div className="calendar-view-organizer">{event.organizer?.emailAddress?.name}</div> </td> </tr> ) } )} </React.Fragment> ) } }
Добавьте следующие утверждения
import
в верхнюю часть Calendar.tsx.import CalendarDayRow from './CalendarDayRow'; import './Calendar.css';
Замените существующее
return
заявление следующим кодом.Это разделяет события на соответствующие дни и отрисовывка раздела таблицы для каждого дня.
Сохраните изменения и перезапустите приложение. Щелкните ссылку Календарь , и теперь приложение должно отрисовки таблицы событий.
Создание нового события
В этом разделе вы добавим возможность создания событий в календаре пользователя.
Добавление метода в GraphService
Откройте ./src/GraphService.ts и добавьте следующую функцию для создания нового события.
export async function createEvent(accessToken: string, newEvent: Event): Promise<Event> { const client = getAuthenticatedClient(accessToken); // POST /me/events // JSON representation of the new event is sent in the // request body return await client .api('/me/events') .post(newEvent); }
Создание новой формы события
Создайте новый файл в каталоге ./src с именем NewEvent.tsx и добавьте следующий код.
import React from 'react'; import { NavLink as RouterNavLink, Redirect } from 'react-router-dom'; import { Button, Col, Form, FormGroup, Label, Input, Row } from 'reactstrap'; import { Attendee, Event } from 'microsoft-graph'; import { config } from './Config'; import withAuthProvider, { AuthComponentProps } from './AuthProvider'; import { createEvent } from './GraphService'; interface NewEventState { subject: string; attendees: string; start: string; end: string; body: string; disableCreate: boolean; redirect: boolean; } class NewEvent extends React.Component<AuthComponentProps, NewEventState> { constructor(props: any) { super(props); this.state = { subject: '', attendees: '', start: '', end: '', body: '', disableCreate: true, redirect: false } this.handleUpdate = this.handleUpdate.bind(this); this.isFormDisabled = this.isFormDisabled.bind(this); this.createEvent = this.createEvent.bind(this); } // Called whenever an input is changed handleUpdate(event: React.ChangeEvent<HTMLInputElement>) { // Set the state value that maps to the input var newState: any = { [event.target.name]: event.target.value }; this.setState(newState); } // Determines if form is ready to submit // Requires a subject, start, and end isFormDisabled(): boolean { return this.state.subject.length === 0 || this.state.start.length === 0 || this.state.end.length === 0; } // Creates the event when user clicks Create async createEvent() { // Get the value of attendees and split into an array var attendeeEmails = this.state.attendees.split(';'); var attendees: Attendee[] = []; // Create an Attendee object for each email address attendeeEmails.forEach((email) => { if (email.length > 0) { attendees.push({ emailAddress: { address: email } }); } }); // Create the Event object var newEvent: Event = { subject: this.state.subject, // Only add if there are attendees attendees: attendees.length > 0 ? attendees : undefined, // Specify the user's time zone so // the start and end are set correctly start: { dateTime: this.state.start, timeZone: this.props.user.timeZone }, end: { dateTime: this.state.end, timeZone: this.props.user.timeZone }, // Only add if a body was given body: this.state.body.length > 0 ? { contentType: "text", content: this.state.body } : undefined } try { // Get the user's access token var accessToken = await this.props.getAccessToken(config.scopes); // Create the event await createEvent(accessToken, newEvent); // Redirect to the calendar view this.setState({ redirect: true }); } catch (err) { this.props.setError('ERROR', JSON.stringify(err)); } } render() { if (this.state.redirect) { return <Redirect to="/calendar" /> } return ( <Form> <FormGroup> <Label for="subject">Subject</Label> <Input type="text" name="subject" id="subject" value={this.state.subject} onChange={this.handleUpdate} /> </FormGroup> <FormGroup> <Label for="attendees">Attendees</Label> <Input type="text" name="attendees" id="attendees" placeholder="Enter a list of email addresses, seperated by a semi-colon" value={this.state.attendees} onChange={this.handleUpdate} /> </FormGroup> <Row form> <Col> <FormGroup> <Label for="start">Start</Label> <Input type="datetime-local" name="start" id="start" value={this.state.start} onChange={this.handleUpdate} /> </FormGroup> </Col> <Col> <FormGroup> <Label for="end">End</Label> <Input type="datetime-local" name="end" id="end" value={this.state.end} onChange={this.handleUpdate} /> </FormGroup> </Col> </Row> <FormGroup> <Label for="body">Body</Label> <Input type="textarea" name="body" id="body" value={this.state.body} onChange={this.handleUpdate} /> </FormGroup> <Button color="primary" className="mr-2" disabled={this.isFormDisabled()} onClick={this.createEvent}>Create</Button> <RouterNavLink to="/calendar" className="btn btn-secondary" exact>Cancel</RouterNavLink> </Form> ) } } export default withAuthProvider(NewEvent);
Откройте ./src/App.tsx
import
и добавьте следующее утверждение в верхнюю часть файла.import NewEvent from './NewEvent';
Добавьте новый маршрут в новую форму события. Добавьте следующий код сразу после других
Route
элементов.<Route exact path="/newevent" render={(props) => <NewEvent {...props} /> } />
Теперь полное
return
утверждение должно выглядеть так.Обновите приложение и просмотрите представление календаря. Нажмите кнопку "Новое событие ". Заполните поля и нажмите кнопку Создать.
Поздравляем!
Вы завершили учебный React Microsoft Graph. Теперь, когда у вас есть рабочее приложение, которое вызывает Microsoft Graph, вы можете экспериментировать и добавлять новые функции. В обзоре microsoft Graph, чтобы увидеть все данные, к ним можно получить доступ с помощью microsoft Graph.
Отзывы
Возникла проблема с этим разделом? Если это так, отправьте нам отзыв, чтобы мы исправили этот раздел.