UNPKG

@holykzm/use-liff

Version:

A custom React hook and provider for LINE Frontend Framework (LIFF).

250 lines (249 loc) 11.2 kB
"use client"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import { jsx as _jsx } from "react/jsx-runtime"; import { useState, useEffect, createContext, useContext, } from "react"; /** * LIFFアプリケーションのコンテキスト。 * LIFFの状態をアプリケーション全体で共有するために使用します。 * * @type {React.Context<LiffContextType>} */ var LiffContext = createContext({ currentUser: null, liffControls: null, liffError: null, isMock: false, }); /** * モック用のLIFFコントロールを作成します。 * 開発環境でLINEプラットフォームに接続せずにテストするためのモックを提供します。 * * @returns {unknown} Liffインターフェースと互換性のあるモックオブジェクト */ var createMockLiff = function () { return { init: function (_a) { var liffId = _a.liffId; return Promise.resolve(); }, getOS: function () { return 'web'; }, getLanguage: function () { return 'ja'; }, getVersion: function () { return '2.0.0'; }, getLineVersion: function () { return null; }, isInClient: function () { return true; }, isLoggedIn: function () { return true; }, login: function () { }, logout: function () { }, getAccessToken: function () { return 'mock-access-token'; }, getIDToken: function () { return 'mock-id-token'; }, getDecodedIDToken: function () { return ({ iss: 'https://access.line.me', sub: 'mock-user-id', aud: 'mock-client-id', exp: 0, iat: 0, auth_time: 0, nonce: '', amr: ['pwd'], name: 'Mock User', picture: '/favicon.ico', email: 'mock@example.com' }); }, getContext: function () { return ({ type: 'utou', utouId: 'mock-utou-id' }); }, getProfile: function () { return Promise.resolve({ userId: 'mock-user-id', displayName: 'Mock User', pictureUrl: '/favicon.ico', statusMessage: 'This is a mock user' }); }, getFriendship: function () { return Promise.resolve({ friendFlag: true }); }, sendMessages: function (messages) { alert("\u30E1\u30C3\u30BB\u30FC\u30B8\u9001\u4FE1: ".concat(JSON.stringify(messages))); return Promise.resolve(); }, openWindow: function (_a) { var url = _a.url; window.open(url, '_blank'); }, closeWindow: function () { alert('ウィンドウを閉じようとしました'); }, scanCode: function () { return Promise.reject(new Error('この機能はモックでは使用できません')); }, scanCodeV2: function () { return Promise.reject(new Error('この機能はモックでは使用できません')); }, getAId: function () { return Promise.resolve('mock-aid'); }, getIFLKAnalysisUA: function () { return Promise.resolve('{}'); }, shareTargetPicker: function (messages) { alert("\u5171\u6709\u30BF\u30FC\u30B2\u30C3\u30C8\u30D4\u30C3\u30AB\u30FC: ".concat(JSON.stringify(messages))); return Promise.resolve({ status: 'success' }); }, permanentLink: { createUrl: function () { return 'https://example.com/mock-permanent-link'; }, createUrlBy: function () { return 'https://example.com/mock-permanent-link'; }, setExtraQueryParam: function () { } }, i18n: { setLang: function () { } }, permission: { query: function () { return Promise.resolve({ state: 'granted' }); }, requestAll: function () { return Promise.resolve({ state: 'granted' }); } }, use: function () { }, isApiAvailable: function () { return true; }, // 他の必要なメソッドがあれば追加 }; }; /** * モック用のプロフィール情報を作成します。 * 開発環境でテスト用のユーザープロフィールを提供します。 * * @returns {Profile} ダミーのユーザープロフィール */ var createMockProfile = function () { return { userId: process.env.NEXT_PUBLIC_MOCK_USER_ID || 'mock-user-id', displayName: 'Mock User', pictureUrl: '/favicon.ico', statusMessage: 'This is a mock user' }; }; /** * LIFF SDKを初期化し、ユーザー情報を取得するカスタムフックです。 * モックモードをサポートしており、環境変数または明示的な設定で有効化できます。 * * @param {string} liffId - LINE Developers ConsoleでLIFFアプリに割り当てられたID * @param {string | null} ifWebMoveTo - LINEアプリ以外で開かれた場合にリダイレクトするURL(省略可) * @returns {object} LIFFの状態を含むオブジェクト * @returns {Profile | null} object.currentUser - 現在のLINEユーザープロフィール情報 * @returns {Liff | null} object.liffControls - LIFF SDKのインスタンス * @returns {string | null} object.liffError - 発生したエラーメッセージ * @returns {boolean} object.isMock - モックモードで動作しているかどうか * * @example * const { currentUser, liffControls, liffError, isMock } = useLiff('1234567890-abcdefgh'); */ export var useLiff = function (liffId, ifWebMoveTo) { if (ifWebMoveTo === void 0) { ifWebMoveTo = null; } var _a = useState(null), currentUser = _a[0], setCurrentUser = _a[1]; var _b = useState(null), liffControls = _b[0], setLiffControls = _b[1]; var _c = useState(null), liffError = _c[0], setLiffError = _c[1]; var _d = useState(false), isMock = _d[0], setIsMock = _d[1]; useEffect(function () { if (!liffId) { console.error("LIFF ID is undefined. Please set it in your LiffProvider."); return; } // 環境変数でMOCKモードかどうかを判断 var isLiffMockMode = typeof window !== 'undefined' && (window.LIFF_MOCK === true || process.env.NEXT_PUBLIC_LIFF_MOCK === 'true'); if (isLiffMockMode) { console.log("LIFF Mock Mode is enabled"); var mockLiff = createMockLiff(); setLiffControls(mockLiff); setCurrentUser(createMockProfile()); setIsMock(true); return; } import("@line/liff") .then(function (liff) { return liff.default; }) .then(function (liff) { if (liff.getLineVersion() === null && ifWebMoveTo) { window.location.href = ifWebMoveTo; return; } liff .init({ liffId: liffId }) .then(function () { setLiffControls(liff); if (liff.isLoggedIn()) { liff.getProfile().then(function (profile) { return setCurrentUser(profile); }); } else { liff.login(); } }) .catch(function (error) { setLiffError(error.toString()); }); }); }, [liffId, ifWebMoveTo]); return { currentUser: currentUser, liffControls: liffControls, liffError: liffError, isMock: isMock }; }; /** * LIFFアプリケーションのプロバイダーコンポーネント。 * LIFF SDKを初期化し、アプリケーション全体でLIFFの状態を共有します。 * * @component * @param {LiffProviderProps} props - コンポーネントのプロパティ * @param {ReactNode} props.children - プロバイダーの子要素 * @param {ComponentType<{ error: string }>} [props.customError] - エラー発生時に表示するカスタムコンポーネント * @param {ReactNode} [props.customLoading] - ロード中に表示するカスタムコンポーネント * @param {string} props.liffId - LINE Developers ConsoleでLIFFアプリに割り当てられたID * @param {string} [props.ifWebMoveTo] - LINEアプリ以外で開かれた場合にリダイレクトするURL * @param {boolean} [props.mock] - モックモードを有効化するかどうか * @returns {JSX.Element} LIFFプロバイダーコンポーネント * * @example * <LiffProvider * liffId="1234567890-abcdefgh" * customError={CustomErrorComponent} * customLoading={<LoadingSpinner />} * ifWebMoveTo="https://example.com" * mock={process.env.NODE_ENV === 'development'} * > * <App /> * </LiffProvider> */ export var LiffProvider = function (_a) { var children = _a.children, CustomError = _a.customError, customLoading = _a.customLoading, liffId = _a.liffId, ifWebMoveTo = _a.ifWebMoveTo, mock = _a.mock; // mockが明示的に指定されている場合は、そのままグローバル変数として設定 useEffect(function () { if (typeof window !== 'undefined' && mock === true) { window.LIFF_MOCK = true; } }, [mock]); var _b = useLiff(liffId, ifWebMoveTo), currentUser = _b.currentUser, liffControls = _b.liffControls, liffError = _b.liffError, isMock = _b.isMock; // ifWebMoveTo を useLiff に渡す var errorComponent = liffError && CustomError ? _jsx(CustomError, { error: liffError }) : null; var loadingComponent = customLoading || _jsx("div", { children: "Loading..." }); return (_jsx(LiffContext.Provider, __assign({ value: { currentUser: currentUser, liffControls: liffControls, liffError: liffError, isMock: isMock } }, { children: errorComponent ? errorComponent : currentUser ? children : loadingComponent }))); }; /** * LIFFコンテキストにアクセスするためのカスタムフック。 * コンポーネント内でLIFFの状態やAPIを使用するために利用します。 * * @returns {LiffContextType} LIFFコンテキストの値 * @returns {Profile | null} LiffContextType.currentUser - 現在のLINEユーザープロフィール情報 * @returns {Liff | null} LiffContextType.liffControls - LIFF SDKのインスタンス * @returns {string | null} LiffContextType.liffError - 発生したエラーメッセージ * @returns {boolean} LiffContextType.isMock - モックモードで動作しているかどうか * * @example * const { currentUser, liffControls, liffError, isMock } = useLiffContext(); * * // ユーザー名を取得 * const userName = currentUser?.displayName || 'ゲスト'; * * // メッセージを送信 * const sendMessage = () => { * if (liffControls) { * liffControls.sendMessages([ * { type: 'text', text: 'こんにちは!' } * ]); * } * }; */ export var useLiffContext = function () { return useContext(LiffContext); };