[Outlook add-in] dialog를 이용한 소셜 로그인 구현하기 - 4

고병표·2023년 7월 16일
0
post-thumbnail

🥐 개요

이번 글은 outlook add-in 안에서 office 제공 함수(dialog)를 사용해서 소셜 로그인을 구현하는 방법과 커스텀 Hooks으로 분리하는 방법, 분리한 Hooks의 사용 방법을 설명할 예정이다.

🍕 dialog란?

앞선 글에 설명한 것처럼 outlook web과 desktop 앱 모두 적용되는 소셜 로그인을 구현하기 위해서는 Microsoft Office에서 제공하는 dialog를 이용해야 합니다.

여기서 dialog란 Microsoft Office 앱의 JavaScript API에서 제공하는 메서드 중 하나이며 Office.context.ui.displayDialogAsync을 이용햐여 Office 앱에서 사용할 수 있습니다.

dialog는 Office 앱의 주 창과는 별개로 표시되며, 사용자와 상호 작용할 수 있는 사용자 인터페이스(인터넷 브라우저)를 제공합니다. 이를 통해 추가적인 정보를 입력하거나 사용자가 필요한 작업을 수행할 수 있습니다.

(dialog 예시 사진)

dialog의 크기, IFrame 내부에서 표시할지, 대화 상자가 열리기 전에 사용자에게 경고 메시지를 표시할지 등 다양한 설정을 할 수 있습니다. (링크 참고)

[공식문서] dialog 설명 및 사용법
[공식문서] dialog Properties

🍔 dialog란 커스텀 훅으로 분리하기

dialog를 사용하기 위해서는 다음과 같이 4가지를 작성해야 합니다.

  • displayDialogAsync를 불러오는 부분
  • dialog를 callback 받는 함수
  • message를 hanlder하는 부분
  • 이동한 페이지에서 다시 부모 컴포넌트에게 메시지를 전달하는 부분

여기까지만 하더라도 코드가 길어져 가독성이 떨어지는데, 보통 소셜 로그인은 여러 개의 provider로 하나의 페이지에서 구현되기 때문에 로직의 분리가 필요한 상황이었습니다.

때문에 프로젝트의 다양한 곳에서 사용할 수 있게 커스텀 훅으로 분리하여 사용했습니다.

⭐️ useDialog 작성

우선 공통적으로 사용되는 Office.context.ui.displayDialogAsync 로딩 부분을 openDialog 함수로 정의했습니다.

그 후 dialogCallback으로 dialog에서 일어나는 다양한 에러 상황에 대한 케이스 정리와 성공적으로 로딩이 되었을때 할 callback를 받는 부분을 구현했습니다.

// @NOTE: dialog 로딩 부분
export const useDialog = () => {
  // @NOTE: 
  const openDialog = (
    url: string,
    callback: Function,
    dialog: Office.Dialog
  ) => {
    Office.context.ui.displayDialogAsync(
      url,
      { width: 50, height: 50 },
      (asyncResult: Office.AsyncResult<Office.Dialog>) =>
        dialogCallback(callback, asyncResult, dialog)
    );
  };
  
  // @NOTE: dialogCallback 부분
  const dialogCallback = (
    callback: Function,
    asyncResult: Office.AsyncResult<Office.Dialog>,
    dialog: Office.Dialog
  ) => {
    if (asyncResult.status === Office.AsyncResultStatus.Failed) {
      switch (asyncResult.error.code) {
        case 12004:
          console.log('Domain is not trusted');
          break;
        case 12005:
          console.log('HTTPS is required');
          break;
        case 12007:
          console.log('A dialog is already opened.');
          break;
        default:
          console.log(asyncResult.error.message);
          break;
      }
    } else {
      dialog = asyncResult.value;
      dialog.addEventHandler(
        Office.EventType.DialogMessageReceived,
        (arg: Office.DialogParentMessageReceivedEventArgs) =>
          callback(arg, dialog)
      );
    }
  };

  return openDialog;
};

export default useDialog;

⭐️ useDialog 프로젝트 적용 및, MessageHandler 작성

그 후 dialog를 사용할 컴포넌트에서 useDialog()를 불러와주고, dialog를 선언했습니다.

여기서 dialog 변수를 useDialog 훅에 포함하지 않고 사용할 컴포넌트에서 선언한 이유는 한 페이지에서 여러 dialog를 사용할 경우 dialog 중복 선언되어 최적화에 문제가 있었고, 이벤트 간섭을 최소한 하기 위함입니다.

openDialog에선 이동을 원하는 URL과 MessageHandler와 아까 선언한 dialog를 파라미터로 받으면 됩니다.

여기서 MessageHandler는 성공적으로 dialog에서 응답을 받을 경우 할 행동을 적의하면 되는데, 중요한 점은 dialog.close() 함수를 마지막에 정의하여 dialog 이벤트를 종료 시켜야 합니다.

dialogCallback

  // @NOTE: 이렇게 불러오고 
  let dialog;
  const openDialog = useDialog();

  ~~ 
  
  // @NOTE: 이벤트 핸들러 정의
    const MessageHandler = (arg, dialog) => {
    ~~
    dialog.close();
  };

  ~~
  
  // @NOTE: 이렇게 사용!
    openDialog(
      "원하는 URL",
      MessageHandler,
      dialog
    )
              

⭐️ 이동한 페이지에서 부모 컴포넌트에게 메시지를 전달하는 부분

이동한 페이지에선 원하는 로직을 작성하면 됩니다.

필자의 경우 Redirect URI 방식으로 각 소셜 로그인을 구현하고, 각 provider에게 전달받은 refresh token이나 id_token등을 전달하였습니다.

이때 주의할 점은 이동한 페이지 안에서 office 제공 함수를 사용할 수 있어야 하며, Office.context.ui.messageParent 메소드를 이용하여 부모 컴포넌트에게 메시지를 전달해야 합니다.

// @NOTR: office 관련 함수 설정
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>
// @NOTE: 전달할 내용을 text에 담아 전달
const handleOfficeContext = (text) => Office.initialize = () => Office.context.ui.messageParent(text);

🥞 마치며

원래 이 시리즈를 작성하면서 계획했던 내용은 여기까지였다. 하지만 최근 다행하? 회사에서 outlook관련 다양한 POC를 진행하게 되면서 새롭게 알게 된 기능들이 있어서 시리즈 작성을 이어갈 예정이다.

여담으로 블로그를 T story로 이전할까 생각 중이다.
최근 들어 글 업로드를 자주 안 하게 되면서, 새로운 동기부여? 가 필요한 시점이라 생각하고 있다.

좀 더 개발자로서 열심히 살려고 한다.

계속..

0개의 댓글