Ejercicio: Creación de una ACE de SPFx con funcionalidades de ubicación geográfica

Completado

En este ejercicio, creará una extensión de tarjeta adaptable (ACE) de SharePoint Framework (SPFx) con la plantilla tarjeta de texto principal que usa las funcionalidades de ubicación geográfica en Conexiones Viva.

El escenario que implementará es una versión simplificada de un servicio de traslado de campus que una gran universidad o empresa tiene para ayudar a los empleados y visitantes a llegar entre edificios. El ACE es para el buceador de un transbordador. El conductor usará la ACE para reservar un viaje e indicar que está en camino de recoger a un pasajero o entregar a un pasajero a su destino.

Requisitos previos

El desarrollo de ACE para conexiones Viva requiere un inquilino de Microsoft 365, SharePoint Online y Conexiones Viva configurados en el inquilino. Use los siguientes recursos para preparar el inquilino:

También necesita las herramientas de desarrollo necesarias instaladas en la estación de trabajo:

Importante

En la mayoría de los casos, instalar la última versión de las siguientes herramientas es la mejor opción. Las versiones enumeradas aquí fueron usadas la última vez que se publicó y se probó este módulo.

Creación de una lista de SharePoint para almacenar los datos

El primer paso consiste en crear una nueva lista de SharePoint para almacenar los datos de cada conductor de lanzadera del campus.

En un explorador, vaya al sitio de SharePoint donde desea probar el proyecto que creará en este ejercicio.

Seleccione New (Nuevo ) y, a continuación, List (Lista ) en las opciones disponibles:

Captura de pantalla de la nueva experiencia de lista.

En el cuadro de diálogo Crear una lista , seleccione Lista en blanco.

Establezca el nombre de la lista en Campus Shuttle y seleccione Crear.

Cuando el explorador se actualice para mostrar la nueva lista, agregue algunas columnas a la lista. Seleccione Agregar columna, Texto y, a continuación, haga clic en el botón Siguiente . En el panel Crear una columna , escriba los valores siguientes y seleccione Guardar:

  • Nombre: OriginLocation
  • Tipo: línea única de texto

Repita este proceso con los siguientes valores para agregar algunas columnas más a la lista:

  • Columna:
    • Nombre: DestinationName
    • Tipo: línea única de texto
  • Columna:
    • Nombre: DestinationLocation
    • Tipo: línea única de texto
  • Columna:
    • Nombre: Estado
    • Tipo: Elección
    • Opciones:
      • Contratado
      • en route
      • disponible

Con la lista para almacenar los datos de nuestra ACE, ahora podemos crear el proyecto.

Creación y preparación del proyecto de SPFx

Abra un símbolo del sistema y muévase a una carpeta donde quiera crear el proyecto SPFx. A continuación, ejecute el generador de Yeoman de SharePoint mediante el comando siguiente:

yo @microsoft/sharepoint

Use lo siguiente para completar el símbolo del sistema que se muestra:

  • ¿Cuál es el nombre de la solución?: AceCampusShuttle
  • ¿Qué tipo de componente del lado cliente se va a crear?: Extensión de tarjeta adaptable
  • ¿Qué plantilla desea usar?: Plantilla de texto principal
  • ¿Cuál es el nombre de la extensión de tarjeta adaptable?: Campus Shuttle

Después de aprovisionar las carpetas necesarias para el proyecto, el generador instalará todos los paquetes de dependencias ejecutando npm install automáticamente. Cuando NPM complete la descarga de todas las dependencias, abra el proyecto en Visual Studio Code.

Adición de datos de ejemplo

La ACE que creará dará al controlador de transporte la opción de seleccionar un destino de una lista de ubicaciones conocidas o seleccionar un punto en un mapa.

Cree un archivo ./src/adaptiveCardExtensions/campusShuttle/assets/campus_locations.json en el proyecto y agregue una matriz para objetos de ubicación. Cada ubicación debe tener una propiedad name, latitude y longitud . O bien, puede pegar el siguiente JSON en el archivo que contiene algunas ubicaciones de la Universidad de Florida en Gainesville, Florida, Estados Unidos.

[
  { "title": "UF: Reitz Student Union", "latitude": 29.6463258, "longitude": -82.3499756 },
  { "title": "UF: The Hub", "latitude": 29.648018, "longitude": -82.345664 },
  { "title": "UF: Department of Computer and Information Science and Engineering", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: Materials Science and Engineering", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: Turlington Hall", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: McCarty Hall A", "latitude": 29.6476101, "longitude": -82.3466208 },
  { "title": "UF: Peabody Hall", "latitude": 29.6502915, "longitude": -82.3433807 },
  { "title": "UF: Norman Hall", "latitude": 29.6486165, "longitude": -82.3398393 },
  { "title": "UF: Warrington College of Business", "latitude": 29.65093, "longitude": -82.3402091 },
  { "title": "UF: Mechanical and Aerospace Engineering Building A", "latitude": 29.6436917, "longitude": -82.3478054 },
  { "title": "UF: New Physics Building (NPB)", "latitude": 29.6439734, "longitude": -82.3506927 },
  { "title": "UF: Murphree Hall", "latitude": 29.6508923, "longitude": -82.3480633 }
]

Adición del asistente del servicio de API REST de SharePoint

A continuación, vamos a agregar un servicio REST de SharePoint al proyecto para controlar toda la lectura y escritura en la lista de SharePoint que creó para almacenar los datos del controlador de transporte.

Cree un nuevo archivo ./src/adaptiveCardExtensions/campusShuttle/sp.service.ts en el proyecto y agréguele el código siguiente:

import { AdaptiveCardExtensionContext } from '@microsoft/sp-adaptive-card-extension-base';
import { SPHttpClient } from '@microsoft/sp-http'

export const STATUS_HIRED = 'hired';
export const STATUS_ENROUTE = 'en route';
export const STATUS_AVAILABLE = 'available';

export interface ILocation {
  latitude: number;
  longitude: number;
}

export interface IListItem {
  ['@odata.type']?: string;
  Id?: string;
  Title: string;
  Status: string;
  OriginLocation?: string | ILocation;
  DestinationName?: string;
  DestinationLocation?: string | ILocation;
}

export const fetchListItem = async (spContext: AdaptiveCardExtensionContext, listId: string): Promise<IListItem> => {
  if (!listId) { return Promise.reject('No listId specified.'); }

  const listApiUrl = `${spContext.pageContext.web.absoluteUrl}/_api/web/lists/GetById(id='${listId}')`;
  const user = spContext.pageContext.user.loginName;

  const response: { value: IListItem[] } = await (await spContext.spHttpClient.get(
    `${listApiUrl}/items/?$select=Id,Title,Status,OriginLocation,DestinationName,DestinationLocation&$filter=Title eq '${user}'&$top=1`,
    SPHttpClient.configurations.v1
  )).json();

  if (response.value.length === 0) { return Promise.resolve(undefined); }

  const convertedTrip = response.value[0];

  if (convertedTrip) {
    const origin = convertedTrip.OriginLocation as string;
    convertedTrip.OriginLocation = <ILocation>{
      latitude: Number(origin.split(',')[0]),
      longitude: Number(origin.split(',')[1])
    };
  }
  if (convertedTrip) {
    const destination = convertedTrip.DestinationLocation as string;
    convertedTrip.DestinationLocation = <ILocation>{
      latitude: Number(destination.split(',')[0]),
      longitude: Number(destination.split(',')[1])
    };
  }

  return Promise.resolve(convertedTrip);
}

const getItemEntityType = async (spContext: AdaptiveCardExtensionContext, listApiUrl: string): Promise<string> => {
  const response: { ListItemEntityTypeFullName: string } = await (await spContext.spHttpClient.get(
    `${listApiUrl}?$select=ListItemEntityTypeFullName`,
    SPHttpClient.configurations.v1
  )).json();

  return response.ListItemEntityTypeFullName;
}

const createListItem = async (
  spContext: AdaptiveCardExtensionContext,
  listApiUrl: string,
  listItem: IListItem): Promise<void> => {

  listItem['@odata.type'] = await getItemEntityType(spContext, listApiUrl);

  await spContext.spHttpClient.post(
    `${listApiUrl}/items`,
    SPHttpClient.configurations.v1,
    {
      headers: {
        'ACCEPT': 'application/json; odata.metadata=none',
        'CONTENT-TYPE': 'application/json'
      },
      body: JSON.stringify(listItem)
    }
  );

  return Promise.resolve();
}

export const upsertListItem = async (spContext: AdaptiveCardExtensionContext, listId: string, listItem: IListItem): Promise<void> => {
  if (!listId) { return Promise.reject('No listId specified.'); }

  const listApiUrl = `${spContext.pageContext.web.absoluteUrl}/_api/web/lists/GetById(id='${listId}')`;

  const originLocationObj = (listItem.OriginLocation as ILocation);
  listItem.OriginLocation = `${originLocationObj.latitude},${originLocationObj.longitude}`;
  const destinationLocationObj = (listItem.DestinationLocation as ILocation);
  listItem.DestinationLocation = `${destinationLocationObj.latitude},${destinationLocationObj.longitude}`;

  if (!listItem['@odata.type']) { return createListItem(spContext, listApiUrl, listItem); }

  await spContext.spHttpClient.post(
    `${listApiUrl}/items(${listItem.Id})`,
    SPHttpClient.configurations.v1,
    {
      headers: { 'IF-MATCH': '*', 'X-HTTP-METHOD': 'MERGE' },
      body: JSON.stringify(<IListItem>{
        Title: listItem.Title,
        Status: listItem.Status,
        OriginLocation: listItem.OriginLocation,
        DestinationName: listItem.DestinationName,
        DestinationLocation: listItem.DestinationLocation
      })
    }
  );

  return Promise.resolve();
}

export const deleteListItem = async (spContext: AdaptiveCardExtensionContext, listId: string, listItemId: number): Promise<void> => {
  if (!listId) { return Promise.reject('No listId specified.'); }
  if (!listItemId) { return Promise.reject('No listItemId specified.'); }

  const listApiUrl = `${spContext.pageContext.web.absoluteUrl}/_api/web/lists/GetById(id='${listId}')`;

  await spContext.spHttpClient.post(
    `${listApiUrl}/items(${listItemId})`,
    SPHttpClient.configurations.v1,
    {
      headers: { 'IF-MATCH': '*', 'X-HTTP-METHOD': 'DELETE' }
    }
  );
}

Este servicio exporta los siguientes elementos que usará en todo el proyecto:

  • Tres constantes () para las opciones de estado:
    • STATUS_AVAILABLE
    • STATUS_ENROUTE
    • STATUS_HIRED
  • fetchListItem(): este método recupera el registro del controlador que ha iniciado sesión actualmente (si está presente).
  • upsertListItem(): este método crea o actualiza un registro de controlador existente.
  • deleteListItem(): este método elimina un registro de controlador cuando están más tiempo en un viaje.

Inicializar el proyecto

Ahora que el proyecto tiene algunas dependencias principales agregadas, ahora vamos a implementar la inicialización de algunas características principales cuando la ACE se cargue por primera vez en la página. Esto implica configurar el estado de la ACE y permitir que el usuario establezca el identificador de la lista que contiene los detalles del viaje del controlador.

Actualice la ACE para permitir que el usuario establezca el identificador de lista de SharePoint.

Busque la clase ACE en el archivo ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts y ábrala en VS Code.

Busque la ICampusShuttleAdaptiveCardExtensionProps interfaz y agregue la listId propiedad para almacenar el identificador de la lista de SharePoint que contiene los registros de estado del controlador:

export interface ICampusShuttleAdaptiveCardExtensionProps {
  title: string;
  listId: string;
}

Busque y abra el archivo ./src/adaptiveCardExtensions/campusShuttle/CampusShuttlePropertyPane.ts. Agregue una nueva PropertyPaneTextField a la groupFields matriz para agregar una opción para que el usuario establezca el identificador de la lista que contiene los registros de estado del controlador:

groupFields: [
  PropertyPaneTextField('title', {
    label: strings.TitleFieldLabel
  }),
  PropertyPaneTextField('listId', {
    label: 'List ID (GUID)'
  })
]

Por último, vuelva al archivo CampusShuttleAdaptiveCardExtension.ts y agregue el siguiente método a la CampusShuttleAdaptiveCardExtension clase . El tiempo de ejecución de SPFx genera este evento cuando cambia el valor de una propiedad en el panel de propiedades. Queremos que nuestra ACE use un cambio en el identificador de la lista para intentar inicializar el estado de la ACE si se encuentra un registro de controlador:

protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
  if (propertyPath === 'listId' && newValue !== oldValue) {
    if (newValue) {
      (async () => {
        const trip = await fetchListItem(this.context, this.properties.listId);
        if (trip) { this.setState({ currentTrip: trip }); }
      })();
    }
  }
}

Actualización del estado de ACE y la vista de tarjeta inicial

Agregue la siguiente import instrucción después de las instrucciones existentes import en el archivo:

import {
  IListItem,
  fetchListItem,
  STATUS_AVAILABLE
} from './sp.service';

Busque la interfaz ICampusShuttleAdaptiveCardExtensionState de estado y agregue la propiedad currentTrip como se muestra en el código siguiente:

export interface ICampusShuttleAdaptiveCardExtensionState {
  currentTrip: IListItem;
}

Inicialice la propiedad state en el método existente onInit() . Reemplace el existente this.state = { }; por el código siguiente para establecer el estado como un recorrido de marcador de posición para el controlador actual:

this.state = {
  currentTrip: {
    Title: this.context.pageContext.user.loginName,
    Status: STATUS_AVAILABLE
  }
};

A continuación, agregue el código siguiente al onInit() método , inmediatamente antes de la return Promise.resolve(); instrucción para recuperar el registro de viaje del controlador actual de la lista de SharePoint. Si se encuentra un viaje coincidente, actualiza el estado de la ACE a este viaje, sobrescribiendo el viaje predeterminado vacío que creó al inicializar el estado.

if (this.properties.listId) {
  const trip = await fetchListItem(this.context, this.properties.listId);
  if (trip) { this.setState({ currentTrip: trip }); }
}

Este código usa la await palabra clave pero la firma del onInit() método, mientras devuelve un Promise, no tiene la palabra clave necesaria async . Actualice la declaración del onInit() método para incluir esta palabra clave:

public async onInit(): Promise<void> { .. }

Quite el control QuickView existente y actualice el CardView inicial.

El último paso antes de probar nuestra ACE es quitar la vista rápida actual. Más adelante, agregaremos varias vistas rápidas nuevas a la ACE.

Para empezar, quite las siguientes líneas del archivo CampusShuttleAdaptiveCardExtension.ts :

  1. Quite la siguiente import instrucción:

    import { QuickView } from './quickView/QuickView';
    
  2. Quite la export declaración del identificador de QuickView:

    export const QUICK_VIEW_REGISTRY_ID: string = 'CampusShuttle_QUICK_VIEW';
    
  3. En el método de onInit() la CampusShuttleAdaptiveCardExtension clase , quite la siguiente instrucción que registra QuickView:

    this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView());
    
  4. Elimine los siguientes archivos del proyecto:

    • ./src/adaptiveCardExtensions/campusShuttle/quickView/template/QuickViewTemplate.json
    • ./src/adaptiveCardExtensions/campusShuttle/quickView/QuickView.ts

A continuación, busque y abra CardView: ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts y realice los siguientes cambios en él:

  1. Busque la instrucción existente import que hace referencia a valores del @microsoft/sp-adaptive-card-extension-base paquete y quite las siguientes referencias:

    • IExternalLinkCardAction
    • IQuickViewCardAction
  2. Busque la instrucción existente import que hace referencia a valores del CampusShuttleAdaptiveCardExtension módulo y quite la referencia a la QUICK_VIEW_REGISTRY_ID constante.

  3. Agregue la siguiente instrucción import después de las instrucciones import existentes:

    import { STATUS_AVAILABLE } from '../sp.service';
    
  4. Reemplace el contenido del miembro del cardButtons() descriptor de acceso por la instrucción siguiente switch . Actualizará esta instrucción switch a lo largo de este ejercicio a medida que agregue nueva funcionalidad a la ACE:

public get cardButtons(): [ICardButton] | [ICardButton, ICardButton] | undefined {
  switch (this.state.currentTrip.Status) {
    default:
      return undefined;
      break;
  }
}
  1. Actualice el miembro del data() descriptor de acceso para devolver las propiedades que se usarán para la tarjeta actual:
public get data(): IPrimaryTextCardParameters {
  return {
    primaryText: strings.PrimaryText,
    description: (this.state.currentTrip.Status === STATUS_AVAILABLE)
      ? `available for hire`
      : `TODO`,
    title: this.properties.title
  };
}
  1. Quite el miembro de descriptor de acceso existente onCardSelection() porque cardview ya no tiene botones.

Prueba de la ACE

Ahora está listo para probar el estado inicial de nuestra ACE.

En la consola, ejecute la siguiente instrucción:

gulp serve --nobrowser

En un explorador, vaya al área de trabajo hospedada de SharePoint en el mismo sitio donde creó la lista para almacenar registros de controladores. Por ejemplo, si la dirección URL de lista es https://contoso.sharepoint.com/sites/MSLearningTeam/Lists/Campus%20Shuttle/AllItems.aspx, la dirección URL del área de trabajo hospedada es https://contoso.sharepoint.com/sites/MSLearningTeam/_layouts/15/workbench.aspx.

Seleccione el + icono y, a continuación, seleccione Campus Shuttle en el cuadro de herramientas:

Captura de pantalla del cuadro de herramientas de SPFx.

Mantenga el mouse sobre el componente ACE y seleccione el icono de lápiz para abrir el panel de propiedades:

Captura de pantalla de la experiencia de edición de una ACE.

Escriba el identificador de la lista de SharePoint en el cuadro de texto Id . de lista y cierre el panel de propiedades seleccionando el icono X en la esquina superior derecha.

Sugerencia

Puede obtener el identificador de una lista en la dirección URL de la página de configuración de la lista.

En primer lugar, vaya a la lista y, a continuación, seleccione el icono de engranaje en la barra de conjuntos de aplicaciones y, a continuación, seleccione el vínculo Configuración de lista.

La cadena de consulta de la página de configuración de lista contiene una propiedad List , como List=%7B93f11b8b-6201-4199-b263-3ca78408a73b%7D. Se trata de una cadena codificada en dirección URL que contiene GUID rodeado por {}. Quite el %7B prefijo y %7D el sufijo para obtener el identificador de la lista. Por ejemplo, este identificador de lista es 93f11b8b-6201-4199-b263-3ca78408a73b.

Captura de pantalla de cómo obtener la página de configuración de lista.

No observará ningún cambio en la representación de la ACE porque todavía no hay ningún registro en la lista.

En este momento, el proyecto mínimo está funcionando. Puede empezar a agregar interactividad a la ACE con QuickViews.

Agregar capacidad para crear viajes con QuickViews

Ahora implementará la funcionalidad para permitir que el usuario actual agregue un nuevo viaje mediante la ACE. Cuando crean un viaje, tienen tres cosas que deben establecer:

  • ubicación de origen/inicio para el viaje
  • ubicación de destino para el viaje
  • si el conductor del transbordador está en ruta para recoger a un pasajero de la ubicación de origen, o si ha recogido al pasajero y en el camino hacia el destino

Para implementar esto, creará varias vistas rápidas y usará la funcionalidad de ubicación geográfica de las ACE en Conexiones Viva.

Creación de StartTrip QuickView

Empiece por crear un nuevo archivo StartTripCard.json en la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView/template y agregue el siguiente JSON. Esto establece el contenido de QuickView mediante una tarjeta adaptable.

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.5",
  "body": [
    {
      "type": "TextBlock",
      "text": "Start a trip",
      "size": "Large",
      "weight": "Bolder"
    },
    {
      "type": "TextBlock",
      "text": "Select trip status:",
      "size": "medium",
      "weight": "Bolder"
    },
    {
      "id": "tripType",
      "type": "Input.ChoiceSet",
      "value": "$trip.Status",
      "choices": [
        {
          "title": "en route to pickup",
          "value": "en route"
        },
        {
          "title": "starting trip",
          "value": "hired"
        }
      ]
    },
    {
      "type": "TextBlock",
      "text": "Set trip details:",
      "size": "medium",
      "weight": "Bolder"
    }
  ],
  "actions": [
    {
      "id": "originLocation",
      "type": "Action.Submit",
      "title": "(1) Select trip origin from map"
    },
    {
      "id": "destinationLocation",
      "type": "Action.Submit",
      "title": "(2) Select / set trip destination"
    },
    {
      "id": "save",
      "type": "Action.Submit",
      "title": "Save trip",
      "style": "positive"
    }
  ]
}

A continuación, cree el archivo StartTrip.ts en la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView . Este archivo contendrá la clase que implementa QuickView.

Agregue el siguiente código al archivo:

import {
  ISPFxAdaptiveCard,
  BaseAdaptiveCardView,
  IActionArguments
} from '@microsoft/sp-adaptive-card-extension-base';
import * as strings from 'CampusShuttleAdaptiveCardExtensionStrings';
import {
  ICampusShuttleAdaptiveCardExtensionProps,
  ICampusShuttleAdaptiveCardExtensionState
} from '../CampusShuttleAdaptiveCardExtension';

import { IListItem, upsertListItem } from '../sp.service';

export interface IStartTripData {
  title: string;
  trip: IListItem;
}

export class StartTrip extends BaseAdaptiveCardView<
  ICampusShuttleAdaptiveCardExtensionProps,
  ICampusShuttleAdaptiveCardExtensionState,
  IStartTripData
> {

  public get data(): IStartTripData {
    return {
      title: strings.Title,
      trip: this.state.currentTrip
    };
  }

  public get template(): ISPFxAdaptiveCard {
    return require('./template/StartTripCard.json');
  }

  public onAction(action: IActionArguments): void {
    if (action.type === 'Submit') {
      if (action.data.tripType) {
        const trip = this.state.currentTrip;
        trip.Status = action.data.tripType;
        this.setState({ currentTrip: trip });
      }

      if (action.id === 'originLocation') {
        // TODO QuickView originLocation
      } else if (action.id === 'destinationLocation') {
        // TODO QuickView destinationLocation
      } else if (action.id === 'save') {
        (async () => {
          await upsertListItem(this.context, this.properties.listId, this.state.currentTrip);
          // TODO QuickView save
        })();
      }
    }
  }

}

La StartTrip clase de este archivo contiene tres miembros:

  • data(): este miembro de descriptor de acceso devuelve un objeto al motor de representación de tarjeta adaptable que se usará para enlazar propiedades a la tarjeta adaptable que se usa para implementar QuickView.
  • template(): este miembro de descriptor de acceso devuelve un objeto JSON que contiene la definición de tarjeta adaptable.
  • onAction(): se llama a este método cuando se producen ciertas acciones en la tarjeta adaptable. En este punto, el código simplemente guarda el valor del tipo de viaje (en la ruta | contratada) y contiene los marcadores de posición para más tarjetas de QuickView que agregará al proyecto.

Para simplificar la referencia a las vistas rápidas que contendrá el proyecto, agregue un nuevo archivo index.ts a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView con el código siguiente:

export * from './StartTrip';

Registro y referencia a StartTrip QuickView

Para usar este nuevo QuickView, debe registrarlo con el navegador QuickView de ACE. Abra el archivo ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts .

Agregue la siguiente import instrucción después de las instrucciones de importación existentes para importar la nueva vista rápida que creó:

import {
  StartTrip
} from './quickView';

Busque la constante inmediatamente antes de la declaración de clase CampusShuttleAdaptiveCardExtension y agregue la siguiente declaración:

export const QUICK_VIEW_START_TRIP_REGISTRY_ID: string = 'CampusShuttle_StartTrip_QUICK_VIEW';

A continuación, en CampusShuttleAdaptiveCardExtension el método de onInit() clase , busque la línea siguiente:

this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView());

Agregue la línea siguiente para registrar starttrip QuickView con el navegador QuickView.

this.quickViewNavigator.register(QUICK_VIEW_START_TRIP_REGISTRY_ID, () => new StartTrip());

Adición de StartTrip QuickView a CardView

El último paso es agregar QuickView a nuestro CardView para usarlo. Busque y abra el archivo siguiente en VS Code: ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts

Busque la import instrucción que importa la propiedad y la interfaz de estado del archivo que contiene la declaración de clase ACE. Agregue la constante que agregó que contiene el identificador de StartTrip QuickView:

import {
  ICampusShuttleAdaptiveCardExtensionProps,
  ICampusShuttleAdaptiveCardExtensionState,
  QUICK_VIEW_START_TRIP_REGISTRY_ID   // << add this
} from '../CampusShuttleAdaptiveCardExtension';

A continuación, en la cardButtons() instrucción del descriptor de switch acceso, agregue case la instrucción antes de la existente default para mostrar un botón para reservar un viaje cuando el estado del controlador actual esté disponible:

switch (this.state.currentTrip.Status) {
  case STATUS_AVAILABLE:
    return [{
      title: 'Book a Trip',
      action: {
        type: 'QuickView',
        parameters: { view: QUICK_VIEW_START_TRIP_REGISTRY_ID }
      }
    }];
    break;
  default:
    return undefined;
    break;
}

Pruebe la ACE para comprobar que QuickView funciona. Si anteriormente detuvo el servidor web local, reinícielo ejecutando lo siguiente en la consola:

gulp serve --nobrowser

Vaya al área de trabajo hospedada de SharePoint para ver campus shuttle ACE:

Captura de pantalla de la ACE representada en modo de edición.

Observe el botón Reservar un viaje en CardView. Pruébelo seleccionando el vínculo Vista previa en la sección superior derecha de la navegación superior. Esta página cambiará del modo de edición al modo de visualización, donde puede seleccionar el botón:

Captura de pantalla de la ACE representada en modo de vista previa o de presentación.

Ahora vamos a implementar la funcionalidad de StartTrip QuickView.

Adición de funcionalidad a StartTrip QuickView

Ahora agregará tres Vistas rápidas que usará StartTrip QuickView. Uno controla la configuración de la ubicación de origen del viaje, otro controla la selección o configuración del destino del viaje y el último actúa como aviso de confirmación al guardar el viaje.

  • Agregue un nuevo archivo SetOriginCard.json a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView/template con el código siguiente:

    {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "size": "large",
          "text": "${title}"
        },
        {
          "type": "TextBlock",
          "text": "${description}",
          "wrap": true
        }
      ],
      "actions": [
        {
          "id": "originLocation",
          "type": "VivaAction.GetLocation",
          "title": "Select location on the map",
          "parameters": {
            "chooseLocationOnMap": true
          }
        }
      ]
    }
    

    Observe que la acción única de esta tarjeta adaptable se establece en el tipo VivaAction.GetLocation. Esto pedirá al usuario que seleccione una ubicación de su dispositivo y devuelva las coordenadas.

  • Implemente SetOrigin QuickView agregando un nuevo archivo SetOrigin.ts a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView con el código siguiente:

    import {
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView,
      IGetLocationActionArguments
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
    
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import { ILocation, IListItem } from '../sp.service';
    
    export interface ISetOriginData {
      title: string;
      description: string;
      trip: IListItem;
    }
    
    export class SetOrigin extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      ISetOriginData
    > {
      public get data(): ISetOriginData {
        return {
          title: 'Set trip starting location',
          description: 'Select the trip origin location by selecting it on the map.',
          trip: this.state.currentTrip
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/SetOriginCard.json');
      }
    
      public onAction(action: IGetLocationActionArguments): void {
        if (action.type === 'VivaAction.GetLocation'){
    
          const currentTrip = this.state.currentTrip;
          currentTrip.OriginLocation = <ILocation> {
            latitude: action.location.latitude,
            longitude: action.location.longitude
          };
    
          this.setState({ currentTrip: currentTrip });
    
          this.quickViewNavigator.pop();
        }
      }
    }
    

    Observe cómo este código, dentro del onAction() controlador de eventos, obtiene la ubicación seleccionada cuando la tarjeta adaptable envía VivaAction.GetLocation . Establece la ubicación seleccionada en el viaje y actualiza el objeto de viaje en el estado de la ACE. La última llamada a this.quickViewNavigator.pop() quita esta vista rápida de la pila de QuickView, lo que desencadena una nueva representación de la siguiente vista rápida en la pila.

Ahora implemente una vista rápida similar para establecer la ubicación de destino:

  • Agregue un nuevo archivo SetDestinationCard.json a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView/template con el código siguiente:

    {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "text": "${title}"
        },
        {
          "type": "TextBlock",
          "text": "${description}"
        },
        {
          "type": "TextBlock",
          "text": "Select a known location..."
        },
        {
          "id": "knownDestinationSelection",
          "type": "Input.ChoiceSet",
          "choices": [
            {
              "$data": "${campus_locations}",
              "title": "${title}",
              "value": "${latitude},${longitude}"
            }
          ]
        },
        {
          "type": "TextBlock",
          "text": "... or select a specific location on the map:"
        }
      ],
      "actions": [
        {
          "id": "destinationLocation",
          "type": "VivaAction.GetLocation",
          "title": "Select trip destination from map",
          "parameters": { "chooseLocationOnMap": true }
        },
        {
          "id": "save",
          "type": "Action.Submit",
          "title": "Save destination location",
          "style": "positive"
        }
      ]
    }
    

    Esta tarjeta adaptable es similar a la que se usa en la ubicación de origen de la manera en que permite al usuario seleccionar una ubicación en el mapa o seleccionar una lista de ubicaciones predefinidas. Estas ubicaciones predefinidas se encuentran en el archivo ./src/adaptiveCardExtensions/campusShuttle/assets/campus_locations.json .

    La tarjeta adaptable también contiene otro botón de acción de envío. A diferencia de QuickView de origen establecido, este botón se usará para cerrar la vista rápida de destino establecida, ya que el usuario tiene dos opciones para seleccionar un destino de viaje.

  • Implemente SetDestination QuickView agregando un nuevo archivo SetDestination.ts a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView con el código siguiente:

    import {
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView,
      IActionArguments,
      IGetLocationActionArguments
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import { ILocation, IListItem } from '../sp.service';
    
    import { sortBy } from '@microsoft/sp-lodash-subset';
    
    interface ICampusLocations {
      title: string;
      latitude: number;
      longitude: number;
    }
    
    export interface ISetDestinationData {
      title: string;
      description: string;
      campus_locations: ICampusLocations[];
      trip: IListItem;
    }
    
    const LOCATIONS = require('../assets/campus_locations.json');
    
    export class SetDestination extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      ISetDestinationData
    > {
      public get data(): ISetDestinationData {
        return {
          title: 'Set trip destination location',
          description: 'Pick from a list of known locations, or set the destination by selecting it on the map.',
          campus_locations: sortBy(LOCATIONS, (l) => l.title),
          trip: this.state.currentTrip
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/SetDestinationCard.json');
      }
    
      public onAction(action: IActionArguments | IGetLocationActionArguments): void {
        const currentTrip = this.state.currentTrip;
    
        // if picked a location on the map...
        if (action.type === 'VivaAction.GetLocation') {
          currentTrip.DestinationLocation = <ILocation>{
            latitude: action.location.latitude,
            longitude: action.location.longitude
          };
          this.setState({ currentTrip: currentTrip });
        } else if (action.type === 'Submit' && action.id === 'save') {
          // else, check if picked location from dropdown and save it
          if (action.data.knownDestinationSelection) {
            currentTrip.DestinationLocation = <ILocation>{
              latitude: Number(action.data.knownDestinationSelection.split(',')[0]),
              longitude: Number(action.data.knownDestinationSelection.split(',')[1])
            };
    
           const selectedLocation = LOCATIONS.filter((knownLocation: any) => (
              knownLocation.latitude === (currentTrip.DestinationLocation as ILocation).latitude
              && knownLocation.longitude === (currentTrip.DestinationLocation as ILocation).longitude
            ))[0];
            currentTrip.DestinationName = selectedLocation.title;
          }
          this.setState({ currentTrip: currentTrip });
          this.quickViewNavigator.pop();
        }
      }
    
    }
    

El último paso es agregar una vista rápida de confirmación de guardado al proyecto:

  • Agregue un nuevo archivo SaveTripCard.json a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView/template con el código siguiente:

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [{
        "type": "TextBlock", "text": "${title}"
      }],
      "actions": [{
        "type": "Action.Submit",
        "id": "close",
        "title": "Close"
      }]
    }
    
  • Implemente SaveTrip QuickView agregando un nuevo archivo SaveTrip.ts a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView con el código siguiente:

    import {
      BaseAdaptiveCardView,
      IActionArguments,
      ISPFxAdaptiveCard
     } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    export interface ISaveTripData {
      title: string;
    }
    
    export class SaveTrip extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      ISaveTripData
    > {
      public get data(): ISaveTripData {
        return {
          title: 'Trip saved successfully.'
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/SaveTripCard.json');
      }
    
      public onAction(action: IActionArguments): void {
        if (action.id === 'close') {
          this.quickViewNavigator.close();
        }
      }
    }
    

Para usar estas tres vistas rápidas nuevas, debe registrarlas:

  1. Abra el archivo ./src/adaptiveCardExtensions/campusShuttle/quickView/index.ts y exporte las nuevas vistas rápidas:

    export * from './StartTrip';
    export * from './SetOrigin';      // << add
    export * from './SetDestination'; // << add
    export * from './SaveTrip';       // << add
    
  2. Abra el archivo ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts .

    1. Actualice la instrucción existente import que agregó para importar starttrip QuickView para hacer referencia a las tres vistas rápidas nuevas:

      import {
        StartTrip,
        SetOrigin,
        SetDestination,
        SaveTrip
      } from './quickView';
      
    2. Busque las constantes que declaran los identificadores de CardView y QuickView y agregue los siguientes identificadores para las nuevas vistas rápidas:

      export const QUICK_VIEW_SET_ORIGIN_REGISTRY_ID: string = 'CampusShuttle_SetOrigin_QUICK_VIEW';
      export const QUICK_VIEW_SET_DESTINATION_REGISTRY_ID: string = 'CampusShuttle_SetDestination_QUICK_VIEW';
      export const QUICK_VIEW_SAVE_TRIP_REGISTRY_ID: string = 'CampusShuttle_SaveTrip_QUICK_VIEW';
      
    3. En el onInit() método de la CampusShuttleAdaptiveCardExtension clase , agregue el código siguiente después de la llamada existente a la this.quickViewNavigator.register() instrucción que registró starttrip QuickView:

      this.quickViewNavigator.register(QUICK_VIEW_SET_ORIGIN_REGISTRY_ID, () => new SetOrigin());
      this.quickViewNavigator.register(QUICK_VIEW_SET_DESTINATION_REGISTRY_ID, () => new SetDestination());
      this.quickViewNavigator.register(QUICK_VIEW_SAVE_TRIP_REGISTRY_ID, () => new SaveTrip());
      

El último paso es conectar las vistas rápidas a la vista rápida de StartTrip existente.

  1. Busque y abra el archivo ./src/adaptiveCardExtensions/campusShuttle/quickView/StartTrip.ts .

  2. Busque la instrucción existente import que hace referencia a las interfaces de estado y propiedad en el CampusShuttleCopilotAdaptiveCardExtension módulo. Actualícelo para importar las tres constantes de las tres nuevas vistas rápidas:

    import {
      ICampusShuttleCopilotAdaptiveCardExtensionProps,
      ICampusShuttleCopilotAdaptiveCardExtensionState,
      QUICK_VIEW_SET_ORIGIN_REGISTRY_ID,
      QUICK_VIEW_SET_DESTINATION_REGISTRY_ID,
      QUICK_VIEW_SAVE_TRIP_REGISTRY_ID
    } from '../CampusShuttleAdaptiveCardExtension';
    
  3. Implemente SetOrigin QuickView reemplazando el comentario // TODO QuickView originLocation en el onAction() método por lo siguiente:

    this.quickViewNavigator.push(QUICK_VIEW_SET_ORIGIN_REGISTRY_ID);
    
  4. Implemente setDestination QuickView reemplazando el comentario // TODO QuickView destinationLocation en el onAction() método por lo siguiente:

    this.quickViewNavigator.push(QUICK_VIEW_SET_DESTINATION_REGISTRY_ID);
    
  5. Implemente saveTrip QuickView reemplazando el comentario // TODO QuickView save en el onAction() método por lo siguiente:

    this.quickViewNavigator.push(QUICK_VIEW_SAVE_TRIP_REGISTRY_ID);
    

Observe que cada una de estas llamadas inserta una vista rápida en el navegador. Esto desencadena una nueva representación de QuickView mediante el nuevo elemento de la pila. Recuerde que anteriormente, estábamos sacando vistas rápidas de la pila.

El último paso es actualizar la pantalla CardView cuando se ha reservado un viaje.

  1. Busque y abra el archivo ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts .

  2. Reemplace la instrucción existente import , import { STATUS_AVAILABLE } from '../sp.service';, por el código siguiente:

    import {
      ILocation,
      STATUS_AVAILABLE,
      STATUS_ENROUTE,
      STATUS_HIRED
    } from '../sp.service';
    
  3. Actualice la switch instrucción del cardButtons() método al código siguiente.

    switch (this.state.currentTrip.Status) {
      case STATUS_AVAILABLE:
        return [{
          title: 'Book a Trip',
          action: {
            type: 'QuickView',
            parameters: { view: QUICK_VIEW_START_TRIP_REGISTRY_ID }
          }
        }];
        break;
      case STATUS_ENROUTE:
        return [
          {
            title: 'View pickup location',
            action: {
              type: 'VivaAction.ShowLocation',
              parameters: {
                locationCoordinates: {
                  latitude: (this.state.currentTrip.OriginLocation as ILocation).latitude,
                  longitude: (this.state.currentTrip.OriginLocation as ILocation).longitude
                }
              }
            }
          }
        ];
        break;
      case STATUS_HIRED:
        return [
          {
            title: 'View dropoff location',
            action: {
              type: 'VivaAction.ShowLocation',
              parameters: {
                locationCoordinates: {
                  latitude: (this.state.currentTrip.DestinationLocation as ILocation).latitude,
                  longitude: (this.state.currentTrip.DestinationLocation as ILocation).longitude
                }
              }
            }
          }
        ];
        break;
      default:
        return undefined;
        break;
    }
    

    Estos cambios mostrarán condicionalmente diferentes botones y texto en función del estado del controlador de transporte actual. Observe que ahora estamos usando la acción VivaAction.ShowLocation de CardView para mostrar las ubicaciones de origen y destino especificadas.

  4. Por último, actualice la return instrucción del data() método al código siguiente.

    return {
      primaryText: strings.PrimaryText,
      description: (this.state.currentTrip.Status === STATUS_AVAILABLE)
        ? `available for hire`
        : (this.state.currentTrip.Status === STATUS_ENROUTE)
          ? `Booked - ${STATUS_ENROUTE} to pickup...`
          : (this.state.currentTrip.DestinationName)
            ? `Hired - driving passenger to ${this.state.currentTrip.DestinationName}...`
            : `Hired - driving passenger to destination...`,
      title: this.properties.title
    };
    

    Tenga en cuenta que esto cambiará el mensaje condicional en función del estado del viaje del conductor del transbordador.

Experiencia de creación de un viaje de prueba

En este punto, puede probar la experiencia de creación de viajes completa en el explorador.

Si anteriormente detuvo el servidor web local, reinícielo ejecutando lo siguiente en la consola:

gulp serve --nobrowser

Vaya al área de trabajo hospedada de SharePoint para ver campus shuttle ACE.

Las ACE solo mostrarán un botón en CardView cuando el tamaño de la tarjeta esté establecido en Medio. Mientras la página está en modo de edición, abra el panel de propiedades y cambie el tamaño de la tarjeta a Grande para que ambos botones aparezcan en CardView.

A continuación, seleccione el botón Vista previa en la parte superior derecha de la barra de herramientas.

Para empezar, seleccione el botón Reservar un viaje en el CardView inicial. Muestra la vista rápida Iniciar un viaje que probó anteriormente.

Seleccione el botón (1) Seleccionar origen del viaje desde el mapa para cargar SetOrigin QuickView. Ahora, seleccione seleccionar la ubicación en el botón de mapa . Si no ha concedido a su explorador acceso a su ubicación, se le pedirá que lo haga. Debe aprobar esta solicitud para que la acción VivaAction.GetLocation funcione:

Captura de pantalla del símbolo del sistema del explorador para conceder acceso a la ubicación.

Después de conceder al explorador acceso a su ubicación, aparecerá un cuadro de diálogo con un mapa. Center the map on the location for the pickup location for the trip, select the pickup and select the Share Location button.

Captura de pantalla que selecciona la ubicación de origen para la recogida del viaje.

Seleccione el botón (2) Seleccionar o establecer destino de viaje para cargar la vista rápida SetDestination. Esta vez, seleccione una de las ubicaciones conocidas en el cuadro desplegable y seleccione el botón Guardar ubicación de destino .

Captura de pantalla que selecciona la ubicación de destino para el viaje.

Por último, seleccione el estado del viaje para en la ruta de recogida y seleccione el botón Guardar viaje .

Captura de pantalla que muestra la vista rápida de confirmación de guardado.

Con el viaje guardado, observe que CardView ahora muestra diferentes botones y texto en función del contexto actual.

Captura de pantalla de CardView cuando el conductor está en ruta a una recogida del viaje.

Por último, vaya a la lista que contiene los datos del viaje para ver cómo se almacenan los datos para nuestro viaje de prueba:

Captura de pantalla del viaje en la lista de SharePoint.

El Campus Shuttle ACE está en buena forma para la creación de viajes. Los dos últimos pasos consisten en implementar los escenarios en los que el conductor está en ruta para recoger a un pasajero y conducir al pasajero a su destino.

Agregar funcionalidad cuando se dirige a la recogida de pasajeros

Ahora vamos a implementar el escenario cuando el conductor está en ruta para recoger a un pasajero.

  • Agregue un nuevo archivo UpdateTripCard.json a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView/template con el código siguiente:

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "weight": "Bolder",
          "text": "${title}"
        }
      ],
      "actions": [
        {
          "id": "cancel",
          "type": "Action.Submit",
          "title": "Cancel Current Trip"
        },
        {
          "id": "pickup",
          "type": "Action.Submit",
          "title": "Pickup Passenger",
          "style": "positive"
        }
      ]
    }
    
  • Implemente UpdateTrip QuickView agregando un nuevo archivo UpdateTrip.ts a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView con el código siguiente:

    import {
      IActionArguments,
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import {
      STATUS_HIRED,
      upsertListItem
    } from '../sp.service';
    
    export interface IUpdateTripData {
      title: string;
    }
    
    export class UpdateTrip extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      IUpdateTripData
    > {
      public get data(): IUpdateTripData {
        return {
          title: 'Update the existing trip'
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/UpdateTripCard.json');
      }
    
      public onAction(action: IActionArguments): void {
        if (action.type !== 'Submit') { return; }
    
        switch (action.id) {
          case 'cancel':
            // TODO QuickView cancelTrip
            break
          case 'pickup':
            // update current item status
            const trip = this.state.currentTrip;
            trip.Status = STATUS_HIRED;
    
            // save to list
            (async () => {
              await upsertListItem(this.context, this.properties.listId, trip);
            })();
    
            // update ACE
            this.setState({ currentTrip: trip });
    
            this.quickViewNavigator.close();
            break
          default:
            return;
        }
      }
    
    }
    

Nuestro proyecto necesita un paso de confirmación si el conductor quiere eliminar un viaje, ya sea cancelándolo o entregando un pasajero. Para implementar esto, usaremos una vista rápida de confirmación única que controlará dinámicamente ambos casos.

  • Agregue un nuevo archivo ConfirmationCard.json a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView/template con el código siguiente:

    {
      "schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.5",
      "body": [
        {
          "type": "TextBlock",
          "text": "${title}",
          "size": "Large"
        },
        {
          "type": "TextBlock",
          "text": "${description}"
        }
      ],
      "actions": [
        {
          "id": "confirm",
          "type": "Action.Submit",
          "title": "${title}",
          "style": "positive"
        }
      ]
    }
    
  • Implemente la vista rápida de confirmación agregando un nuevo archivo ConfirmationQuickView.ts a la carpeta ./src/adaptiveCardExtensions/campusShuttle/quickView con el código siguiente:

    import {
      IActionArguments,
      ISPFxAdaptiveCard,
      BaseAdaptiveCardView
    } from '@microsoft/sp-adaptive-card-extension-base';
    import {
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState
    } from '../CampusShuttleAdaptiveCardExtension';
    
    import {
      deleteListItem,
      STATUS_AVAILABLE
    } from '../sp.service';
    
    export interface IConfirmationQuickViewData {
      title: string;
      description: string;
    }
    
    export class ConfirmationQuickView extends BaseAdaptiveCardView<
      ICampusShuttleAdaptiveCardExtensionProps,
      ICampusShuttleAdaptiveCardExtensionState,
      IConfirmationQuickViewData
    > {
      constructor(private confirmType: 'cancel' | 'complete') {
        super();
      }
    
      public get data(): IConfirmationQuickViewData {
        return {
          title: `${this.confirmType.substring(0,1).toUpperCase()}${this.confirmType.substring(1,this.confirmType.length)} Trip`,
          description: `Are you sure you want to ${this.confirmType} the trip?`
        };
      }
    
      public get template(): ISPFxAdaptiveCard {
        return require('./template/ConfirmationCard.json');
      }
    
      public onAction(action: IActionArguments): void {
        if (action.type === 'Submit' && action.id === 'confirm') {
          (async () => {
            // delete list item
            await deleteListItem(this.context, this.properties.listId, Number(this.state.currentTrip.Id));
          })();
    
          // update state to initial value
          this.setState({
            currentTrip: {
              Title: this.context.pageContext.user.loginName,
              Status: STATUS_AVAILABLE
            }
          });
    
          // close
          this.quickViewNavigator.close();
        }
      }
    }
    

Para usar estas tres vistas rápidas nuevas, debe registrarlas:

  1. Abra el archivo ./src/adaptiveCardExtensions/campusShuttle/quickView/index.ts y exporte las nuevas vistas rápidas:

    // .. existing export statements
    export * from './UpdateTrip';
    export * from './ConfirmationQuickView';
    
  2. Abra el archivo ./src/adaptiveCardExtensions/campusShuttle/CampusShuttleAdaptiveCardExtension.ts .

    1. Actualice el existente import para importar las vistas rápidas para hacer referencia a las nuevas vistas rápidas:

      import {
        StartTrip,
        SetOrigin,
        SetDestination,
        SaveTrip,
        UpdateTrip,            // << add
        ConfirmationQuickView  // << add
      } from './quickView';
      
    2. Busque las constantes que declaran los identificadores de CardView y QuickView y agregue los siguientes identificadores para las nuevas vistas rápidas:

      export const QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID: string = 'CampusShuttleCopilot_CancelTrip_QUICK_VIEW';
      export const QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID: string = 'CampusShuttleCopilot_CompleteTrip_QUICK_VIEW';
      export const QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID: string = 'CampusShuttleCopilot_UpdateTrip_QUICK_VIEW';
      

      Observe cómo las dos primeras constantes no hacen referencia al QuickView de confirmación? Esto se debe a que vamos a crear dos implementaciones del mismo QuickView.

    3. En el onInit() método de la CampusShuttleAdaptiveCardExtension clase , agregue el código siguiente después de la llamada existente a la this.quickViewNavigator.register() instrucción que registró starttrip QuickView:

      this.quickViewNavigator.register(QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID, () => new ConfirmationQuickView('cancel'));
      this.quickViewNavigator.register(QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID, () => new ConfirmationQuickView('complete'));
      this.quickViewNavigator.register(QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID, () => new UpdateTrip());
      

El último paso es conectar las vistas rápidas a las vistas rápidas y cardview existentes.

  1. Busque y abra el archivo ./src/adaptiveCardExtensions/campusShuttle/cardView/CardView.ts .

    1. Busque la instrucción existente import que hace referencia a las interfaces de estado y propiedad en el CampusShuttleCopilotAdaptiveCardExtension módulo. Actualícela para importar las tres constantes de la actualización y complete las nuevas vistas rápidas:

      import {
        ICampusShuttleAdaptiveCardExtensionProps,
        ICampusShuttleAdaptiveCardExtensionState,
        QUICK_VIEW_START_TRIP_REGISTRY_ID,
        QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID,    // << add
        QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID   // << add
      } from '../CampusShuttleAdaptiveCardExtension';
      
    2. En el cardButton() método de descriptor de acceso, actualice la instrucción switch para agregar más botones:

      1. Agregue el botón siguiente a la case STATUS_ENROUTEreturn instrucción :

        {
          title: 'Update Trip',
          action: {
            type: 'QuickView',
            parameters: { view: QUICK_VIEW_UPDATE_TRIP_REGISTRY_ID }
          }
        }
        
      2. Agregue el botón siguiente a la case STATUS_HIREDreturn instrucción :

        {
          title: 'Complete Trip',
          action: {
            type: 'QuickView',
            parameters: { view: QUICK_VIEW_COMPLETE_TRIP_REGISTRY_ID }
          }
        }
        
  2. Busque y abra el archivo ./src/adaptiveCardExtensions/campusShuttle/quickView/UpdateTrip.ts .

    1. Busque la instrucción existente import que hace referencia a las interfaces de estado y propiedad en el CampusShuttleCopilotAdaptiveCardExtension módulo. Actualícela para importar las tres constantes de la actualización y complete las nuevas vistas rápidas:

      import {
        ICampusShuttleAdaptiveCardExtensionProps,
        ICampusShuttleAdaptiveCardExtensionState,
        QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID    // << add
      } from '../CampusShuttleAdaptiveCardExtension';
      
  3. Implemente SetOrigin QuickView reemplazando el comentario // TODO QuickView cancelTrip en el onAction() método por lo siguiente:

    this.quickViewNavigator.push(QUICK_VIEW_CANCEL_TRIP_REGISTRY_ID);
    

Experiencia de administración de viajes de prueba

En este punto, puede probar la experiencia de administración de viajes en el explorador.

Si anteriormente detuvo el servidor web local, reinícielo ejecutando lo siguiente en la consola:

gulp serve --nobrowser

Vaya al área de trabajo hospedada de SharePoint para ver la ACE de campus shuttle y seleccione el botón Vista previa en la parte superior derecha de la barra de herramientas.

Observe que CardView ahora contiene un botón Actualizar viaje .

Captura de pantalla de la versión actualizada de CardView.

Seleccione el botón Actualizar viaje y observe que hay dos opciones para cancelar o recoger a un pasajero.

Captura de pantalla de UpdateTrip QuickView.

Al seleccionar el botón Cancelar viaje actual , se restablecerá el estado de ACE y se eliminará el registro del controlador de la lista de SharePoint. Al seleccionar el botón Recoger pasajeros , se actualizará el viaje, tanto en el estado ACE como en el elemento de lista de SharePoint, para cambiar el estado del viaje de en ruta a contratado.

Seleccione el botón Pickup Passenger (Pasajeros de recogida ). Observe que el contexto de CardView y los botones cambian para indicar el cambio al estado del viaje:

Captura de pantalla de CardView cuando el conductor lleva al pasajero al destino.

Por último, seleccione el botón Completar viaje para ver la vista rápida de confirmación y, a continuación, seleccione el botón Completar viaje para confirmar. Esto completará el viaje.

Captura de pantalla de la vista rápida de confirmación.

En este ejercicio, ha creado una ACE de SPFx con la opción Tarjeta de texto principal que usa las funcionalidades de ubicación geográfica en Conexiones Viva.

Comprobar sus conocimientos

1.

¿Cómo pueden los desarrolladores hacer que CardViews y QuickViews sean dinámicos con datos contextuales?

2.

Al usar la acción VivaConnections.SelectMedia, ¿cómo guardan los desarrolladores las imágenes seleccionadas en una biblioteca de documentos de SharePoint?

3.

Para establecer la ubicación en la acción VivaLocation.ShowLocation, los desarrolladores pueden proporcionar las coordenadas GPS como latitud y longitud o la dirección de la calle de la ubicación.