Crear aplicaciones de React de página única con Microsoft Graph
Este tutorial te enseña a crear una aplicación React de una sola página que use la API de Microsoft Graph para recuperar información de calendario para un usuario.
Sugerencia
Si prefiere descargar el tutorial completado, puede descargar o clonar el repositorio GitHub archivo.
Requisitos previos
Antes de iniciar este tutorial, debes tenerNode.js e Yarn instalados en el equipo de desarrollo. Si no tienes Node.js o Yarn, visita los vínculos anteriores para ver las opciones de descarga.
También debe tener una cuenta personal de Microsoft con un buzón en Outlook.com, o una cuenta de Trabajo o escuela de Microsoft. Si no tienes una cuenta de Microsoft, hay un par de opciones para obtener una cuenta gratuita:
- Puedes suscribirte a una nueva cuenta personal de Microsoft.
- Puedes suscribirte al programa Microsoft 365 desarrolladores para obtener una suscripción Microsoft 365 gratuita.
Nota
Este tutorial se escribió con Node versión 14.15.0 y Yarn versión 1.22.10. Los pasos de esta guía pueden funcionar con otras versiones, pero eso no se ha probado.
Comentarios
Proporcione cualquier comentario sobre este tutorial en el repositorio GitHub usuario.
Crear una aplicación de React de página única
En esta sección, crearás una nueva React aplicación.
Abra la interfaz de línea de comandos (CLI), vaya a un directorio donde tenga derechos para crear archivos y ejecute los siguientes comandos para crear una nueva React aplicación.
yarn create react-app graph-tutorial --template typescript
Cuando finalice el comando, cambie al directorio graph-tutorial'** de la CLI y ejecute el siguiente comando para iniciar un servidor web local.
yarn start
Nota
Si no tienes yarn instalado, puedes usarlo en
npm start
su lugar.
El explorador predeterminado se abre https://localhost:3000/ con una página React predeterminada. Si el explorador no se abre, ábralo y busque https://localhost:3000/ para comprobar que la nueva aplicación funciona.
Agregar paquetes de nodo
Antes de seguir adelante, instale algunos paquetes adicionales que usará más adelante:
- react-router-dom para el enrutamiento declarativo dentro de la React aplicación.
- bootstrap para el estilo y componentes comunes.
- react-bootstrap para React componentes basados en Bootstrap.
- date-fns para dar formato a fechas y horas.
- windows-iana para traducir Windows zonas horarias al formato IANA.
- msal-react para autenticar a Azure Active Directory y recuperar tokens de acceso.
- microsoft-graph-client para realizar llamadas a Microsoft Graph.
Ejecute el siguiente comando en la 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
Diseñar la aplicación
Empieza creando un contexto para la aplicación.
Cree un nuevo archivo en el directorio ./src denominado AppContext.tsx y agregue las instrucciones
import
siguientes.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';
Agregue el siguiente código.
Agregue la siguiente función al final de ./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 }; }
Completará la implementación de este contexto en secciones posteriores.
Crea una barra de navegación para la aplicación. Cree un nuevo archivo en el
./src
directorio denominado y agregue el siguienteNavBar.tsx
código.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> ); } }
Crea una página principal para la aplicación. Cree un nuevo archivo en el
./src
directorio denominado y agregue el siguienteWelcome.tsx
código.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> ); } }
Cree una presentación de mensaje de error para mostrar mensajes al usuario. Cree un nuevo archivo en el
./src
directorio denominado y agregue el siguienteErrorMessage.tsx
código.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> ); } }
Abra el archivo
./src/index.css
y reemplace todo su contenido por lo siguiente.body { padding-top: 4.5rem; } .alert-pre { word-wrap: break-word; word-break: break-all; white-space: pre-wrap; }
Abra
./src/App.tsx
y reemplace todo su contenido por lo siguiente.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> ); }
Agregue un archivo de imagen de su elección denominado no-profile-photo.png en el directorio ./public/images. Esta imagen se usará como foto del usuario cuando el usuario no tenga ninguna foto en Microsoft Graph.
Guarde todos los cambios y reinicie la aplicación. Ahora, la aplicación debe tener un aspecto muy diferente.
Registrar la aplicación en el portal
En este ejercicio, creará un nuevo registro de aplicaciones web de Azure AD mediante el Centro Azure Active Directory administración.
Abra un explorador y vaya al centro de administración de Azure Active Directory. Inicie sesión con una cuenta personal (también conocida como: cuenta Microsoft) o una cuenta profesional o educativa.
Seleccione Azure Active Directory en el panel de navegación izquierdo y, a continuación, seleccione Registros de aplicaciones en Administrar.
Nota
Los usuarios de Azure AD B2C solo pueden ver Registros de aplicaciones (heredados). En este caso, vaya directamente a https://aka.ms/appregistrations .
Seleccione Nuevo registro. En la página Registrar una aplicación, establezca los valores siguientes.
- Establezca Nombre como
React Graph Tutorial
. - Establezca Tipos de cuenta admitidos en Cuentas en cualquier directorio de organización y cuentas personales de Microsoft.
- En URI de redirección, establezca la primera lista desplegable en
Single-page application (SPA)
y establezca el valorhttp://localhost:3000
.
- Establezca Nombre como
Elija Registrar. En la React Graph tutorial, copie el valor del identificador de aplicación (cliente) y guárdelo, lo necesitará en el paso siguiente.
Agregar autenticación de Azure AD
En este ejercicio, extenderá la aplicación desde el ejercicio anterior para admitir la autenticación con Azure AD. Esto es necesario para obtener el token de acceso OAuth necesario para llamar a Microsoft Graph. En este paso, integrará la biblioteca de biblioteca de autenticación de Microsoft en la aplicación.
Cree un nuevo archivo en el directorio ./src denominado Config.ts y agregue el siguiente código.
export const config = { appId: 'YOUR_APP_ID_HERE', redirectUri: 'http://localhost:3000', scopes: [ 'user.read', 'mailboxsettings.read', 'calendars.readwrite' ] };
Reemplace
YOUR_APP_ID_HERE
por el identificador de aplicación del Portal de registro de aplicaciones.Importante
Si usas el control de código fuente como git, ahora sería un buen momento para excluir el archivo del control de código fuente para evitar la pérdida involuntaria del identificador de la
Config.ts
aplicación.
Implementar el inicio de sesión
En esta sección, implementará un proveedor de autenticación, iniciar sesión y cerrar sesión.
Abra ./src/index.tsx y agregue las siguientes
import
instrucciones en la parte superior del archivo.import { PublicClientApplication, EventType, EventMessage, AuthenticationResult } from '@azure/msal-browser'; import config from './Config';
Agregue el siguiente código antes de la
ReactDOM.render
línea.Este código crea una instancia del objeto de la biblioteca MSAL, comprueba las cuentas almacenadas en caché y registra una devolución de llamada para establecer la cuenta activa después de un inicio de sesión
PublicClientApplication
correcto.Actualice el
App
elemento de la llamada para pasar la propiedad in denominadaReactDOM.render
msalInstance
pca
.Abra ./src/App.tsx y agregue el siguiente código después de la última
import
instrucción.Reemplace la función
App
existente por lo siguiente.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> ); }
Esto encapsula todos los demás elementos con el elemento, lo que hace que el estado de autenticación y la adquisición
MsalProvider
de tokens estén disponibles.Abra ./src/AppContext.tsx y agregue la siguiente
import
instrucción en la parte superior del archivo.import config from './Config';
Agregue la siguiente línea en la parte superior de la
useProvideAppContext
función.const msal = useMsal();
Reemplace la
const authProvider = undefined;
línea por lo siguiente.Reemplace la función
signIn
existente por lo siguiente.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); };
Guarde los cambios y actualice el explorador. Haga clic en el botón de inicio de sesión y verá una ventana emergente que carga
https://login.microsoftonline.com
. Inicie sesión con su cuenta de Microsoft y consiente los permisos solicitados. La página de la aplicación debe actualizarse y mostrar el token.
Obtener detalles del usuario
En esta sección modificará la función para obtener los detalles del usuario signIn
de Microsoft Graph.
Cree un nuevo archivo en el directorio ./src denominado GraphService.ts y agregue el siguiente código.
Esto implementa la función, que inicializa el cliente de Microsoft Graph con el
getUser
proporcionado y obtiene el perfil delAuthProvider
usuario.Abra ./src/AppContext.tsx y agregue la siguiente
import
instrucción en la parte superior del archivo.import { getUser } from './GraphService';
Reemplace la función
signIn
existente por el siguiente código.Reemplace la función
signOut
existente por lo siguiente.Agregue la siguiente
useEffect
llamada dentrouseProvideAppContext
de .Guarde los cambios e inicie la aplicación, después de iniciar sesión, debe volver a la página principal, pero la interfaz de usuario debe cambiar para indicar que ha iniciado sesión.
Haga clic en el avatar del usuario en la esquina superior derecha para obtener acceso al vínculo Cerrar sesión. Al hacer clic en Cerrar sesión, se restablece la sesión y se devuelve a la página principal.
Almacenar y actualizar tokens
En este momento, la aplicación tiene un token de acceso, que se envía en el Authorization
encabezado de las llamadas API. Este es el token que permite a la aplicación tener acceso al Graph microsoft en nombre del usuario.
Sin embargo, este token es de corta duración. El token expira una hora después de su emisión. Aquí es donde el token de actualización resulta útil. El token de actualización permite a la aplicación solicitar un nuevo token de acceso sin requerir que el usuario vuelva a iniciar sesión.
Dado que la aplicación usa la biblioteca MSAL, no es necesario implementar ninguna lógica de actualización o almacenamiento de tokens. El PublicClientApplication
token se almacena en caché en la sesión del explorador. El método primero comprueba el token almacenado en caché y, si no ha acquireTokenSilent
expirado, lo devuelve. Si ha expirado, usa el token de actualización en caché para obtener uno nuevo. Este método se usará más en el siguiente módulo.
Obtener una vista de calendario
En este ejercicio, incorporará el Graph Microsoft en la aplicación. Para esta aplicación, usará la biblioteca de microsoft-graph-client para realizar llamadas a Microsoft Graph.
Obtener eventos del calendario desde Outlook
Abra ./src/GraphService.ts y agregue la siguiente función.
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; } }
Tenga en cuenta lo que está haciendo este código.
- La dirección URL a la que se llamará es
/me/calendarview
. - El
header
método agrega el encabezadoPrefer: outlook.timezone=""
a la solicitud, lo que hace que las horas de la respuesta se den en la zona horaria preferida del usuario. - El
query
método agrega los parámetrosstartDateTime
yendDateTime
, definiendo la ventana de tiempo para la vista de calendario. - El
select
método limita los campos devueltos para cada evento a solo aquellos que la vista usará realmente. - El
orderby
método ordena los resultados por la fecha y hora en que se crearon, siendo el elemento más reciente el primero. - El
top
método limita los resultados de una sola página a 25 eventos. - Si la respuesta contiene un
@odata.nextLink
valor, que indica que hay más resultados disponibles,PageIterator
se usa un objeto para paginar la colección para obtener todos los resultados.
- La dirección URL a la que se llamará es
Cree un React para mostrar los resultados de la llamada. Cree un nuevo archivo en el directorio ./src denominado Calendar.tsx y agregue el siguiente código.
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> ); }
Por ahora, esto simplemente representa la matriz de eventos en JSON en la página.
Agrega este nuevo componente a la aplicación. Abra
./src/App.tsx
y agregue la siguiente instrucciónimport
a la parte superior del archivo.import Calendar from './Calendar';
Agregue el siguiente componente justo después del existente
<Route>
.<Route exact path="/calendar" render={(props) => <Calendar {...props} /> } />
Guarde los cambios y reinicie la aplicación. Inicie sesión y haga clic en el vínculo Calendario de la barra de navegación. Si funciona todo, debería ver un volcado JSON de eventos en el calendario del usuario.
Mostrar los resultados
Ahora puede actualizar el componente Calendar
para mostrar los eventos de una manera más fácil de usar.
Cree un nuevo archivo en el directorio
./src
denominado yCalendar.css
agregue el siguiente código..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; }
Cree un React para representar eventos en un solo día como filas de tabla. Cree un nuevo archivo en el directorio
./src
denominado yCalendarDayRow.tsx
agregue el siguiente código.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> ) } }
Agregue las siguientes
import
instrucciones a la parte superior de Calendar.tsx.import CalendarDayRow from './CalendarDayRow'; import './Calendar.css';
Reemplace la instrucción existente
return
por el código siguiente.Esto divide los eventos en sus respectivos días y representa una sección de tabla para cada día.
Guarda los cambios y reinicia la aplicación. Haz clic en el vínculo Calendario y la aplicación ahora debe representar una tabla de eventos.
Crear un nuevo evento
En esta sección, agregará la capacidad de crear eventos en el calendario del usuario.
Agregar método a GraphService
Abra ./src/GraphService.ts y agregue la siguiente función para crear un nuevo evento.
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); }
Crear nuevo formulario de evento
Cree un nuevo archivo en el directorio ./src denominado NewEvent.tsx y agregue el siguiente código.
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);
Abra ./src/App.tsx y agregue la siguiente
import
instrucción a la parte superior del archivo.import NewEvent from './NewEvent';
Agregue una nueva ruta al nuevo formulario de evento. Agregue el siguiente código justo después de los demás
Route
elementos.<Route exact path="/newevent" render={(props) => <NewEvent {...props} /> } />
La instrucción
return
completa ahora debería tener este aspecto.Actualice la aplicación y vaya a la vista de calendario. Haga clic en el botón Nuevo evento. Rellene los campos y haga clic en Crear.
¡Enhorabuena!
Ha completado el tutorial React microsoft Graph. Ahora que tienes una aplicación de trabajo que llama a Microsoft Graph, puedes experimentar y agregar nuevas características. Visite la información general de Microsoft Graph para ver todos los datos a los que puede acceder con Microsoft Graph.
Comentarios
Proporcione cualquier comentario sobre este tutorial en el repositorio GitHub archivo.
¿Tiene algún problema con esta sección? Si es así, envíenos sus comentarios para que podamos mejorarla.