@holykzm/use-liff
Version:
A custom React hook and provider for LINE Frontend Framework (LIFF).
250 lines (249 loc) • 11.2 kB
JavaScript
"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); };