アプリケーションへのコール・パネル・コンポーネントの追加
前のトピックでは、基本的なJETアプリケーションを構築する方法と、それをFusionメディア・ツールバーにデプロイする方法を示します。
次に、着信コール通知と、メディア・ツールバー・アプリケーションでコールを受け入れるか切断するボタンを表示する必要があります。 これを行うには、要件に基づいてUI要素をレンダリングするロジックを構築します。 このシリーズのステップの一部として、コール通知の表示に必要なUI要素、およびコールの受入れと切断のボタンは、カスタムJETコンポーネントとしてカプセル化されます。
コール・パネル・コンポーネントの状態
コール・パネル・コンポーネントには、次の3つの状態があります:
- 着信: エージェントが着信コールを受信すると、コール・パネル・コンポーネントは着信状態になります。 また、コール・パネル・コンポーネントは、エージェントが顧客によってまだピック・アップされていない発信コールを開始するときに着信状態になります。 アプリケーション。 この状態では、コール・パネル・コンポーネントには、着信コールに関する情報(Fusionアプリケーションから取得される担当者名)、IVRデータ、コールの受入れまたは拒否用の2つのボタンなどが含まれます。
- 受入済: エージェントが顧客からの着信コールを受け入れると、コール・パネル・コンポーネントは受諾済み状態になります。 顧客がエージェントによって開始された発信コールを受け入れると、コール・パネル・コンポーネントも受諾済み状態になります。 この状態の間、コール・パネル・コンポーネントには、着信コール情報に加えて、コール・ハング・アップ・ボタンとコール・イン・プログレスのアニメーションが表示されます。
- 未接続: エージェントが着信コールを拒否したり、進行中のコールを切断すると、コール・パネル・コンポーネントは切断状態になります。
アプリケーションでのカスタム・コンポーネントの作成
- ターミナルでツールバー・アプリケーションのルート・フォルダを開き、コマンドを実行:
ojet create component call-panel
.これにより、
src/ts/jet-composites
フォルダにcall panel
カスタム・コンポーネントが作成されます。詳細は、「Oracle JET Webコンポーネントの作成」を参照してください。
要件に基づいてコンポーネントのファイルを更新
要件に基づいてコンポーネントのコードを更新するには、次のファイルを参照してください:
src/ts/jet-composites/call-panel-view.html
ファイルを更新するには:<div class="oj-sm-margin-4x oj-flex oj-sm-justify-content-center"> <div class="oj-flex oj-bg-neutral-170 oj-sm-padding-6x call-panel oj-color-invert"> <div class="oj-sm-12 oj-flex oj-sm-flex-direction-column oj-sm-align-items-center oj-sm-justify-content-space-between"> <div class="oj-sm-margin-4x-top oj-flex oj-sm-flex-direction-column oj-sm-align-items-center top-panel"> <div class="oj-flex-item oj-typography-heading-xs oj-sm-margin-5x-bottom"> <!-- Shows the text Incoming Call / Calling in the component based on the call direction --> <oj-bind-if test="[[callContext().direction === 'inbound']]"> Incoming Call </oj-bind-if> <oj-bind-if test="[[callContext().direction === 'outbound']]"> Calling </oj-bind-if> </div> <!-- Adds a phone icon as avatar in the component --> <oj-c-avatar class="oj-avatar-8xl" role="img" icon-class="oj-ux-ico-call-incoming" background="green"></oj-c-avatar> <br/><br/> <div id="progressBarContainer" class="oj-flex-item"> <oj-bind-if test="[[callContext().state === 'ACCEPTED']]"> <!-- Show a call in progress animation during the ACCEPTED state --> <oj-c-progress-bar id="progressBar" aria-label="basic progress bar" value="-1"></oj-c-progress-bar> </oj-bind-if> </div> </div> <!-- Show caller information --> <div class="oj-sm-flex oj-sm-flex-direction-column call-details"> <div class="oj-flex-item oj-typography-heading-md oj-sm-margin-2x-vertical"> <oj-bind-text value="[[callContext().callerName]]"></oj-bind-text> </div> <div class="oj-flex-item oj-typography-subheading-xs"> <oj-bind-text value="[[callContext().phonenumber]]"></oj-bind-text> </div> <table class="ivr-data-table oj-typography-body-sm oj-sm-margin-4x oj-helper-text-align-left"> <oj-bind-for-each data="[[ivrDataProvider]]"> <template> <tr> <td><oj-bind-text value="[[$current.data.key]]"></oj-bind-text></td> <td>:</td> <td><oj-bind-text value="[[$current.data.value]]"></oj-bind-text></td> </tr> </template> </oj-bind-for-each> </table> </div> <div class="oj-flex oj-sm-justify-content-center oj-sm-margin-2x-vertical"> <oj-bind-if test="[[callContext().state === 'ACCEPTED']]"> <oj-c-button id="hold" display="icons" label="hold"> <span slot="startIcon" class="oj-ux-ico-pause-circle"></span> </oj-c-button> </oj-bind-if> </div> <div class="oj-flex oj-sm-justify-content-center"> <!-- Show call accept and disconnect buttons in the component --> <oj-bind-if test="[[callContext().state === 'RINGING' && callContext().direction === 'inbound']]"> <!-- Show call accept button only during inbound call RINGING state --> <oj-c-button id="acceptCall" display="icons" label="Accept" chroming="borderless" on-oj-action="[[ acceptClicked ]]" class="oj-sm-margin-2x-horizontal"> <span slot="startIcon" class="oj-ux-ico-call oj-sm-padding-4x oj-sm-padding-10x-horizontal call-accept"></span> </oj-c-button> </oj-bind-if> <oj-c-button id="declineCall" display="icons" label="Decline" chroming="danger" on-oj-action="[[ disconnectClicked ]]" class="oj-sm-margin-2x-horizontal"> <span slot="startIcon" class="oj-ux-ico-call-end oj-sm-padding-4x oj-sm-padding-10x-horizontal"></span> </oj-c-button> </div> </div> </div> </div>
src/ts/jet-composites/call-panel-viewModel.ts
ファイルを更新するには:"use strict"; import * as ko from "knockout"; import Context = require("ojs/ojcontext"); import Composite = require("ojs/ojcomposite"); import ArrayDataProvider = require('ojs/ojarraydataprovider'); import "oj-c/button"; import "ojs/ojknockout"; import "oj-c/avatar"; import "oj-c/progress-bar"; interface CallContext { phonenumber: string; callerName: string; direction: string; eventId: string; ivrData: { [key: string]: string }; state: string; } export default class ViewModel implements Composite.ViewModel<Composite.PropertiesType> { busyResolve: (() => void); composite: Element; properties: Composite.PropertiesType; callContext: ko.Observable<CallContext>; ivrDataProvider: ArrayDataProvider<string, { [key: string]: string }>; constructor(context: Composite.ViewModelContext<Composite.PropertiesType>) { //At the start of your viewModel constructor const elementContext: Context = Context.getContext(context.element); const busyContext: Context.BusyContext = elementContext.getBusyContext(); const options = { "description": "Web Component Startup - Waiting for data" }; this.busyResolve = busyContext.addBusyState(options); this.composite = context.element; // Properties passed to the component this.properties = context.properties; this.callContext = ko.observable(this.properties.callContext); this.ivrDataProvider = new ArrayDataProvider(this.parseIvrData(), { keyAttributes: 'key' }); //Once all startup and async activities have finished, relocate if there are any async activities this.busyResolve(); } parseIvrData(): any { let data: any[] = []; if (this.callContext()?.ivrData) { data = Object.keys(this.callContext().ivrData).map((key: string) => { return { key: key, value: this.callContext().ivrData[key] } }); } const ivrData: any = ko.observableArray(data); return ivrData; } public acceptClicked: (event: any) => void = (event: any): void => { // Logic to fire and event to the container that the accept button is clicked const formattedEvent: object = {bubbles: true, cancelable: false, detail: {}}; const acceptButtonClickedEvent: CustomEvent = new CustomEvent('acceptButtonClicked', formattedEvent); this.composite.dispatchEvent(acceptButtonClickedEvent); } public disconnectClicked: (event: any) => void = (event: any): void => { // Logic to fire and event to the container that the disconecct button is clicked. // If the call is in ACCEPTED state, the value 'HANGUP' is passed as the event payload to the container, // Otherwise, the value 'REJECT' is passed as the event payload const disconnectionState: string = (this.callContext().state === 'ACCEPTED') ? 'WRAPUP' : 'REJECT'; const formattedEvent: object = {bubbles: true, cancelable: false, detail: { disconnectionState }}; const disconnectButtonClickedEvent: CustomEvent = new CustomEvent('disconnectButtonClicked', formattedEvent); this.composite.dispatchEvent(disconnectButtonClickedEvent); } //Lifecycle methods - implement if necessary activated(context: Composite.ViewModelContext<Composite.PropertiesType>): Promise<any> | void { }; connected(context: Composite.ViewModelContext<Composite.PropertiesType>): void { }; bindingsApplied(context: Composite.ViewModelContext<Composite.PropertiesType>): void { }; propertyChanged(context: Composite.PropertyChangedContext<Composite.PropertiesType>): void { if (context.property === 'callContext') { // Update callContext observable based on the propertyChange this.callContext({...this.callContext(), state: context.value.state}); } }; disconnected(element: Element): void { }; };
src/ts/jet-composites/call-panel-styles.css
ファイルを更新するには:call-panel:not(.oj-complete) { visibility: hidden; } call-panel[hidden] { display: none; } .call-panel { min-height: 450px; min-width: 300px; border-radius: 10px; } .top-panel { color: #dfdfdf; } .call-accept { background-color: #28b328; } .call-accept:hover { background-color: #239b23; } .call-details { text-align: center; color: #ffffff; } .ivr-data-table { color: #c4c4c4; } #progressBarContainer { width: 100%; }
src/ts/jet-composites/component.json
ファイルを更新するには:{ "name": "call-panel", "version": "1.0.0", "jetVersion": "^15.1.0", "displayName": "A user friendly, translatable name of the component.", "description": "A translatable high-level description for the component.", "properties": { "callContext": { "description": "The Call context details.", "displayName": "Call Context", "type": "object" } }, "methods": {}, "events": { "acceptButtonClicked": { "displayName": "acceptButtonClicked", "description": "Will be called when accept button is clicked.", "bubbles": true, "cancelable": true, "detail": { } }, "disconnectButtonClicked": { "displayName": "disconnectButtonClicked", "description": "Will be called when disconnect button is clicked.", "bubbles": true, "cancelable": true, "detail": { } } }, "slots": {} }