@sunggang/ui-lib 0.4.43 → 0.4.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -456,14 +456,20 @@ var LiffContext = /*#__PURE__*/ React.createContext(undefined);
456
456
  var LiffProvider = function(param) {
457
457
  var children = param.children, liffId = param.liffId, _param_localStorageKey = param.localStorageKey, localStorageKey = _param_localStorageKey === void 0 ? "one-gobo-global-login" : _param_localStorageKey, checkTokenUrl = param.checkTokenUrl, loginUrl = param.loginUrl, accountLoginUrl = param.accountLoginUrl, memberInfoUrl = param.memberInfoUrl, _param_openInApp = param.openInApp, openInApp = _param_openInApp === void 0 ? false : _param_openInApp, _param_ignoreCheckAddFriend = param.ignoreCheckAddFriend, ignoreCheckAddFriend = _param_ignoreCheckAddFriend === void 0 ? false : _param_ignoreCheckAddFriend, _param_ignoreRoute = param.ignoreRoute, ignoreRoute = _param_ignoreRoute === void 0 ? false : _param_ignoreRoute, _param_loginByUser = param.loginByUser, loginByUser = _param_loginByUser === void 0 ? false : _param_loginByUser, _param_liffLogin = param.liffLogin, liffLogin = _param_liffLogin === void 0 ? false : _param_liffLogin, customerRedirectUrl = param.customerRedirectUrl, inviteCode = param.inviteCode, handleLoginError = param.handleLoginError;
458
458
  var _useState = _sliced_to_array(React.useState(null), 2), liffObject = _useState[0], setLiffObject = _useState[1];
459
- var _useState1 = _sliced_to_array(React.useState(""), 2), accessToken = _useState1[0], setAccessToken = _useState1[1];
460
- var _useState2 = _sliced_to_array(React.useState(null), 2), liffError = _useState2[0], setLiffError = _useState2[1];
461
- var _useState3 = _sliced_to_array(React.useState(null), 2), loginData = _useState3[0], setLoginData = _useState3[1];
462
- var _useState4 = _sliced_to_array(React.useState(null), 2), userInfo = _useState4[0], setUserInfo = _useState4[1];
463
- var _useState5 = _sliced_to_array(React.useState(null), 2), isFriendship = _useState5[0], setFriendship = _useState5[1];
464
- var _useState6 = _sliced_to_array(React.useState(null), 2), loginType = _useState6[0], setLoginType = _useState6[1];
459
+ var _useState1 = _sliced_to_array(React.useState(false), 2), liffInitialized = _useState1[0], setLiffInitialized = _useState1[1];
460
+ var _useState2 = _sliced_to_array(React.useState(""), 2), accessToken = _useState2[0], setAccessToken = _useState2[1];
461
+ var _useState3 = _sliced_to_array(React.useState(null), 2), liffError = _useState3[0], setLiffError = _useState3[1];
462
+ var _useState4 = _sliced_to_array(React.useState(null), 2), loginData = _useState4[0], setLoginData = _useState4[1];
463
+ var _useState5 = _sliced_to_array(React.useState(null), 2), userInfo = _useState5[0], setUserInfo = _useState5[1];
464
+ var _useState6 = _sliced_to_array(React.useState(null), 2), liffProfile = _useState6[0], setLiffProfile = _useState6[1];
465
+ var _useState7 = _sliced_to_array(React.useState(null), 2), isFriendship = _useState7[0], setFriendship = _useState7[1];
466
+ var _useState8 = _sliced_to_array(React.useState(null), 2), loginType = _useState8[0], setLoginType = _useState8[1];
465
467
  // userInfo 的 localStorage key
466
468
  var userInfoStorageKey = "".concat(localStorageKey, "-userInfo");
469
+ // liff profile 的 localStorage key
470
+ var liffProfileStorageKey = "".concat(localStorageKey, "-liffProfile");
471
+ // liff initialized flag 的 localStorage key
472
+ var liffInitializedStorageKey = "".concat(localStorageKey, "-liffInitialized");
467
473
  // 從 localStorage 載入 userInfo
468
474
  var loadUserInfoFromStorage = function() {
469
475
  try {
@@ -478,14 +484,50 @@ var LiffProvider = function(param) {
478
484
  }
479
485
  return null;
480
486
  };
487
+ // 從 localStorage 載入 LIFF profile
488
+ var loadLiffProfileFromStorage = function() {
489
+ try {
490
+ var stored = window.localStorage.getItem(liffProfileStorageKey);
491
+ if (stored) {
492
+ var parsed = JSON.parse(stored);
493
+ setLiffProfile(parsed);
494
+ return parsed;
495
+ }
496
+ } catch (err) {
497
+ console.error("載入 liffProfile 失敗:", err);
498
+ }
499
+ return null;
500
+ };
481
501
  // 儲存 userInfo 到 localStorage
482
- var saveUserInfoToStorage = function(info) {
502
+ var saveUserInfoToStorage = React.useCallback(function(info) {
483
503
  try {
484
504
  window.localStorage.setItem(userInfoStorageKey, JSON.stringify(info));
485
505
  } catch (err) {
486
506
  console.error("儲存 userInfo 失敗:", err);
487
507
  }
488
- };
508
+ }, [
509
+ userInfoStorageKey
510
+ ]);
511
+ // 儲存 LIFF profile 到 localStorage
512
+ var saveLiffProfileToStorage = React.useCallback(function(info) {
513
+ try {
514
+ window.localStorage.setItem(liffProfileStorageKey, JSON.stringify(info));
515
+ } catch (err) {
516
+ console.error("儲存 liffProfile 失敗:", err);
517
+ }
518
+ }, [
519
+ liffProfileStorageKey
520
+ ]);
521
+ // 儲存 liffInitialized flag 到 localStorage
522
+ var saveLiffInitializedToStorage = React.useCallback(function() {
523
+ try {
524
+ window.localStorage.setItem(liffInitializedStorageKey, "1");
525
+ } catch (err) {
526
+ console.error("儲存 liffInitialized 失敗:", err);
527
+ }
528
+ }, [
529
+ liffInitializedStorageKey
530
+ ]);
489
531
  var fetchMemberInfo = function() {
490
532
  var _ref = _async_to_generator(function(token) {
491
533
  var response, err;
@@ -594,6 +636,13 @@ var LiffProvider = function(param) {
594
636
  // token 無效時清除 userInfo
595
637
  setUserInfo(null);
596
638
  window.localStorage.removeItem(userInfoStorageKey);
639
+ // token 無效也清除 liff 相關快取與已初始化標記
640
+ try {
641
+ window.localStorage.removeItem(liffProfileStorageKey);
642
+ window.localStorage.removeItem(liffInitializedStorageKey);
643
+ } catch (e) {
644
+ // ignore
645
+ }
597
646
  return [
598
647
  3,
599
648
  7
@@ -703,41 +752,37 @@ var LiffProvider = function(param) {
703
752
  // 初始化 LIFF
704
753
  var initializeLiff = function() {
705
754
  var _ref = _async_to_generator(function(isValid) {
706
- var customFetch, liff, originalFetch, lineToken, redirectUri, e, tempFriendship, friendship, friendFlag, error, err;
755
+ var _sdk_getAccessToken, _sdk_isLoggedIn, imported, sdk, lineToken, redirectUri, tempFriendship, friendship, friendFlag, error, err;
707
756
  return _ts_generator(this, function(_state) {
708
757
  switch(_state.label){
709
758
  case 0:
710
759
  _state.trys.push([
711
760
  0,
712
- 16,
761
+ 10,
713
762
  ,
714
- 17
763
+ 11
715
764
  ]);
716
- customFetch = // 自訂 fetch 函數,避免每次請求都改變 URL
717
- // eslint-disable-next-line no-inner-declarations
718
- function customFetch(url, options) {
719
- if (url.toString().startsWith("https://liffsdk.line-scdn.net/xlt/") && url.toString().endsWith(".json")) {
720
- url = "".concat(url, "?ts=").concat(Math.random());
721
- }
722
- return originalFetch(url, options);
723
- };
765
+ // 確保 LIFF 已初始化(只執行一次)
724
766
  return [
725
767
  4,
726
- Promise.resolve().then(function () { return require('./index.cjs3.js'); })
768
+ ensureLiffInitialized()
727
769
  ];
728
770
  case 1:
729
- liff = _state.sent().liff;
730
- originalFetch = window.fetch;
731
- window.fetch = customFetch;
732
- if (openInApp && !(liff === null || liff === void 0 ? void 0 : liff.isInClient()) && (liff === null || liff === void 0 ? void 0 : liff.getOS()) !== "web") window.location.href = "line://app/".concat(liffId);
733
- console.log("LIFF init succeeded.");
734
- setLiffObject(liff);
735
- lineToken = liff === null || liff === void 0 ? void 0 : liff.getAccessToken();
736
- // 未登入先進行登入(呼叫 login 後立即 return,避免後續執行 init)
737
- if (!liff.isLoggedIn()) {
771
+ _state.sent();
772
+ return [
773
+ 4,
774
+ Promise.resolve().then(function () { return require('./index.cjs3.js'); })
775
+ ];
776
+ case 2:
777
+ imported = _state.sent();
778
+ sdk = liffObject || imported.liff;
779
+ setLiffObject(sdk);
780
+ lineToken = sdk === null || sdk === void 0 ? void 0 : (_sdk_getAccessToken = sdk.getAccessToken) === null || _sdk_getAccessToken === void 0 ? void 0 : _sdk_getAccessToken.call(sdk);
781
+ // 未登入先進行登入(呼叫 login 後立即 return,避免後續執行)
782
+ if (!(sdk === null || sdk === void 0 ? void 0 : (_sdk_isLoggedIn = sdk.isLoggedIn) === null || _sdk_isLoggedIn === void 0 ? void 0 : _sdk_isLoggedIn.call(sdk))) {
738
783
  redirectUri = customerRedirectUrl || "".concat(window.location.href);
739
784
  if (liffLogin) {
740
- liff.login({
785
+ sdk.login({
741
786
  redirectUri: redirectUri
742
787
  });
743
788
  return [
@@ -747,105 +792,54 @@ var LiffProvider = function(param) {
747
792
  if (loginByUser || ignoreRoute) return [
748
793
  2
749
794
  ];
750
- liff.login({
795
+ sdk.login({
751
796
  redirectUri: redirectUri
752
797
  });
753
798
  return [
754
799
  2
755
800
  ];
756
801
  }
757
- if (!!liffId) return [
758
- 3,
759
- 2
760
- ];
761
- console.warn("liffId 未提供,跳過 liff.init()。");
762
- return [
763
- 3,
764
- 8
765
- ];
766
- case 2:
767
- if (!!liff.isLoggedIn()) return [
802
+ tempFriendship = null;
803
+ if (!lineToken) return [
768
804
  3,
769
- 7
805
+ 9
770
806
  ];
771
807
  _state.label = 3;
772
808
  case 3:
773
809
  _state.trys.push([
774
810
  3,
775
- 5,
776
- ,
777
- 6
778
- ]);
779
- return [
780
- 4,
781
- liff.init({
782
- liffId: liffId,
783
- withLoginOnExternalBrowser: false
784
- })
785
- ];
786
- case 4:
787
- _state.sent();
788
- return [
789
- 3,
790
- 6
791
- ];
792
- case 5:
793
- e = _state.sent();
794
- console.error("liff.init() 失敗:", e);
795
- return [
796
- 3,
797
- 6
798
- ];
799
- case 6:
800
- return [
801
- 3,
802
- 8
803
- ];
804
- case 7:
805
- console.log("LIFF 已登入,跳過 liff.init() 以避免重複的 verify/profile 呼叫。");
806
- _state.label = 8;
807
- case 8:
808
- tempFriendship = null;
809
- if (!lineToken) return [
810
- 3,
811
- 15
812
- ];
813
- _state.label = 9;
814
- case 9:
815
- _state.trys.push([
816
- 9,
817
- 12,
811
+ 6,
818
812
  ,
819
- 13
813
+ 7
820
814
  ]);
821
- if (!!liff.isLoggedIn()) return [
815
+ if (!(sdk.isLoggedIn && sdk.isLoggedIn())) return [
822
816
  3,
823
- 11
817
+ 5
824
818
  ];
825
819
  return [
826
820
  4,
827
- liff.getFriendship()
821
+ sdk.getFriendship()
828
822
  ];
829
- case 10:
823
+ case 4:
830
824
  friendship = _state.sent();
831
825
  friendFlag = friendship === null || friendship === void 0 ? void 0 : friendship.friendFlag;
832
826
  setFriendship(friendFlag);
833
827
  tempFriendship = friendFlag;
834
828
  console.log("isFriendship", friendFlag);
835
- _state.label = 11;
836
- case 11:
829
+ _state.label = 5;
830
+ case 5:
837
831
  return [
838
832
  3,
839
- 13
833
+ 7
840
834
  ];
841
- case 12:
835
+ case 6:
842
836
  error = _state.sent();
843
837
  console.error("Error in liff.getFriendship():", error);
844
838
  return [
845
839
  3,
846
- 13
840
+ 7
847
841
  ];
848
- case 13:
842
+ case 7:
849
843
  console.log("isValid", isValid);
850
844
  if (tempFriendship && isValid) return [
851
845
  2
@@ -854,23 +848,23 @@ var LiffProvider = function(param) {
854
848
  4,
855
849
  loginInit(lineToken)
856
850
  ];
857
- case 14:
851
+ case 8:
858
852
  _state.sent();
859
- _state.label = 15;
860
- case 15:
853
+ _state.label = 9;
854
+ case 9:
861
855
  return [
862
856
  3,
863
- 17
857
+ 11
864
858
  ];
865
- case 16:
859
+ case 10:
866
860
  err = _state.sent();
867
861
  setLiffError(err.toString());
868
862
  console.log("LIFF init failed.", err);
869
863
  return [
870
864
  3,
871
- 17
865
+ 11
872
866
  ];
873
- case 17:
867
+ case 11:
874
868
  return [
875
869
  2
876
870
  ];
@@ -881,6 +875,125 @@ var LiffProvider = function(param) {
881
875
  return _ref.apply(this, arguments);
882
876
  };
883
877
  }();
878
+ // 確保 LIFF init 只執行一次且在需要時才執行
879
+ var ensureLiffInitialized = React.useCallback(/*#__PURE__*/ _async_to_generator(function() {
880
+ var storedFlag, customFetch, liff, originalFetch, profile, e1;
881
+ return _ts_generator(this, function(_state) {
882
+ switch(_state.label){
883
+ case 0:
884
+ console.log("ensureLiffInitialized called", liffInitialized);
885
+ // 如果 state 或 localStorage 上已有 initialized 的標記,就視為已初始化
886
+ if (liffInitialized) return [
887
+ 2
888
+ ];
889
+ try {
890
+ storedFlag = window.localStorage.getItem(liffInitializedStorageKey);
891
+ if (storedFlag === "1") {
892
+ setLiffInitialized(true);
893
+ console.log("liffInitialized loaded from storage");
894
+ return [
895
+ 2
896
+ ];
897
+ }
898
+ } catch (e) {
899
+ // ignore
900
+ }
901
+ if (!liffId) {
902
+ console.warn("liffId 未提供,跳過 liff.init()。");
903
+ return [
904
+ 2
905
+ ];
906
+ }
907
+ _state.label = 1;
908
+ case 1:
909
+ _state.trys.push([
910
+ 1,
911
+ 8,
912
+ ,
913
+ 9
914
+ ]);
915
+ customFetch = // 自訂 fetch 函數,避免每次請求都改變 URL
916
+ // eslint-disable-next-line no-inner-declarations
917
+ function customFetch(url, options) {
918
+ if (url.toString().startsWith("https://liffsdk.line-scdn.net/xlt/") && url.toString().endsWith(".json")) {
919
+ url = "".concat(url, "?ts=").concat(Math.random());
920
+ }
921
+ return originalFetch(url, options);
922
+ };
923
+ return [
924
+ 4,
925
+ Promise.resolve().then(function () { return require('./index.cjs3.js'); })
926
+ ];
927
+ case 2:
928
+ liff = _state.sent().liff;
929
+ originalFetch = window.fetch;
930
+ window.fetch = customFetch;
931
+ if (openInApp && !(liff === null || liff === void 0 ? void 0 : liff.isInClient()) && (liff === null || liff === void 0 ? void 0 : liff.getOS()) !== "web") window.location.href = "line://app/".concat(liffId);
932
+ return [
933
+ 4,
934
+ liff.init({
935
+ liffId: liffId,
936
+ withLoginOnExternalBrowser: false
937
+ })
938
+ ];
939
+ case 3:
940
+ _state.sent();
941
+ _state.label = 4;
942
+ case 4:
943
+ _state.trys.push([
944
+ 4,
945
+ 6,
946
+ ,
947
+ 7
948
+ ]);
949
+ return [
950
+ 4,
951
+ liff.getProfile()
952
+ ];
953
+ case 5:
954
+ profile = _state.sent();
955
+ setLiffProfile(profile);
956
+ saveLiffProfileToStorage(profile);
957
+ return [
958
+ 3,
959
+ 7
960
+ ];
961
+ case 6:
962
+ _state.sent();
963
+ return [
964
+ 3,
965
+ 7
966
+ ];
967
+ case 7:
968
+ setLiffObject(liff);
969
+ setLiffInitialized(true);
970
+ saveLiffInitializedToStorage();
971
+ console.log("LIFF initialized.");
972
+ return [
973
+ 3,
974
+ 9
975
+ ];
976
+ case 8:
977
+ e1 = _state.sent();
978
+ console.error("ensureLiffInitialized failed:", e1);
979
+ return [
980
+ 3,
981
+ 9
982
+ ];
983
+ case 9:
984
+ return [
985
+ 2
986
+ ];
987
+ }
988
+ });
989
+ }), [
990
+ liffInitialized,
991
+ liffId,
992
+ openInApp,
993
+ saveLiffInitializedToStorage,
994
+ saveLiffProfileToStorage,
995
+ liffInitializedStorageKey
996
+ ]);
884
997
  var accountLogin = function() {
885
998
  var _ref = _async_to_generator(function(username, password) {
886
999
  var response, token, tokenType, finalToken, err;
@@ -1047,9 +1160,10 @@ var LiffProvider = function(param) {
1047
1160
  return trimmed.toLowerCase().startsWith("bearer ") ? trimmed : "Bearer ".concat(trimmed);
1048
1161
  };
1049
1162
  var searchParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
1050
- // 初始載入時從 localStorage 載入 userInfo
1163
+ // 初始載入時從 localStorage 載入 userInfo 與 LIFF profile
1051
1164
  React.useEffect(function() {
1052
1165
  loadUserInfoFromStorage();
1166
+ loadLiffProfileFromStorage();
1053
1167
  }, []);
1054
1168
  // 客戶端初始化 LIFF
1055
1169
  React.useEffect(function() {
@@ -1127,32 +1241,21 @@ var LiffProvider = function(param) {
1127
1241
  }();
1128
1242
  checkAndInitialize();
1129
1243
  }, []);
1130
- var contextValue = React.useMemo(function() {
1131
- return {
1132
- liffObject: liffObject,
1133
- loginData: loginData,
1134
- userInfo: userInfo,
1135
- accessToken: accessToken,
1136
- liffError: liffError,
1137
- initializeLiff: function() {
1138
- return initializeLiff(false);
1139
- },
1140
- isFriendship: isFriendship,
1141
- ensureLiffTokenValid: ensureLiffTokenValid,
1142
- accountLogin: accountLogin,
1143
- loginType: loginType
1144
- };
1145
- }, [
1146
- liffObject,
1147
- loginData,
1148
- userInfo,
1149
- accessToken,
1150
- liffError,
1151
- isFriendship,
1152
- ensureLiffTokenValid,
1153
- accountLogin,
1154
- loginType
1155
- ]);
1244
+ var contextValue = {
1245
+ liffObject: liffObject,
1246
+ loginData: loginData,
1247
+ userInfo: userInfo,
1248
+ accessToken: accessToken,
1249
+ liffError: liffError,
1250
+ initializeLiff: function() {
1251
+ return initializeLiff(false);
1252
+ },
1253
+ liffProfile: liffProfile,
1254
+ isFriendship: isFriendship,
1255
+ ensureLiffTokenValid: ensureLiffTokenValid,
1256
+ accountLogin: accountLogin,
1257
+ loginType: loginType
1258
+ };
1156
1259
  return /*#__PURE__*/ jsxRuntime.jsx(LiffContext.Provider, {
1157
1260
  value: contextValue,
1158
1261
  children: children
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { createContext, useState, useCallback, useEffect, useMemo, useContext } from 'react';
2
+ import { createContext, useState, useCallback, useEffect, useContext } from 'react';
3
3
 
4
4
  function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
5
5
  try {
@@ -452,14 +452,20 @@ var LiffContext = /*#__PURE__*/ createContext(undefined);
452
452
  var LiffProvider = function(param) {
453
453
  var children = param.children, liffId = param.liffId, _param_localStorageKey = param.localStorageKey, localStorageKey = _param_localStorageKey === void 0 ? "one-gobo-global-login" : _param_localStorageKey, checkTokenUrl = param.checkTokenUrl, loginUrl = param.loginUrl, accountLoginUrl = param.accountLoginUrl, memberInfoUrl = param.memberInfoUrl, _param_openInApp = param.openInApp, openInApp = _param_openInApp === void 0 ? false : _param_openInApp, _param_ignoreCheckAddFriend = param.ignoreCheckAddFriend, ignoreCheckAddFriend = _param_ignoreCheckAddFriend === void 0 ? false : _param_ignoreCheckAddFriend, _param_ignoreRoute = param.ignoreRoute, ignoreRoute = _param_ignoreRoute === void 0 ? false : _param_ignoreRoute, _param_loginByUser = param.loginByUser, loginByUser = _param_loginByUser === void 0 ? false : _param_loginByUser, _param_liffLogin = param.liffLogin, liffLogin = _param_liffLogin === void 0 ? false : _param_liffLogin, customerRedirectUrl = param.customerRedirectUrl, inviteCode = param.inviteCode, handleLoginError = param.handleLoginError;
454
454
  var _useState = _sliced_to_array(useState(null), 2), liffObject = _useState[0], setLiffObject = _useState[1];
455
- var _useState1 = _sliced_to_array(useState(""), 2), accessToken = _useState1[0], setAccessToken = _useState1[1];
456
- var _useState2 = _sliced_to_array(useState(null), 2), liffError = _useState2[0], setLiffError = _useState2[1];
457
- var _useState3 = _sliced_to_array(useState(null), 2), loginData = _useState3[0], setLoginData = _useState3[1];
458
- var _useState4 = _sliced_to_array(useState(null), 2), userInfo = _useState4[0], setUserInfo = _useState4[1];
459
- var _useState5 = _sliced_to_array(useState(null), 2), isFriendship = _useState5[0], setFriendship = _useState5[1];
460
- var _useState6 = _sliced_to_array(useState(null), 2), loginType = _useState6[0], setLoginType = _useState6[1];
455
+ var _useState1 = _sliced_to_array(useState(false), 2), liffInitialized = _useState1[0], setLiffInitialized = _useState1[1];
456
+ var _useState2 = _sliced_to_array(useState(""), 2), accessToken = _useState2[0], setAccessToken = _useState2[1];
457
+ var _useState3 = _sliced_to_array(useState(null), 2), liffError = _useState3[0], setLiffError = _useState3[1];
458
+ var _useState4 = _sliced_to_array(useState(null), 2), loginData = _useState4[0], setLoginData = _useState4[1];
459
+ var _useState5 = _sliced_to_array(useState(null), 2), userInfo = _useState5[0], setUserInfo = _useState5[1];
460
+ var _useState6 = _sliced_to_array(useState(null), 2), liffProfile = _useState6[0], setLiffProfile = _useState6[1];
461
+ var _useState7 = _sliced_to_array(useState(null), 2), isFriendship = _useState7[0], setFriendship = _useState7[1];
462
+ var _useState8 = _sliced_to_array(useState(null), 2), loginType = _useState8[0], setLoginType = _useState8[1];
461
463
  // userInfo 的 localStorage key
462
464
  var userInfoStorageKey = "".concat(localStorageKey, "-userInfo");
465
+ // liff profile 的 localStorage key
466
+ var liffProfileStorageKey = "".concat(localStorageKey, "-liffProfile");
467
+ // liff initialized flag 的 localStorage key
468
+ var liffInitializedStorageKey = "".concat(localStorageKey, "-liffInitialized");
463
469
  // 從 localStorage 載入 userInfo
464
470
  var loadUserInfoFromStorage = function() {
465
471
  try {
@@ -474,14 +480,50 @@ var LiffProvider = function(param) {
474
480
  }
475
481
  return null;
476
482
  };
483
+ // 從 localStorage 載入 LIFF profile
484
+ var loadLiffProfileFromStorage = function() {
485
+ try {
486
+ var stored = window.localStorage.getItem(liffProfileStorageKey);
487
+ if (stored) {
488
+ var parsed = JSON.parse(stored);
489
+ setLiffProfile(parsed);
490
+ return parsed;
491
+ }
492
+ } catch (err) {
493
+ console.error("載入 liffProfile 失敗:", err);
494
+ }
495
+ return null;
496
+ };
477
497
  // 儲存 userInfo 到 localStorage
478
- var saveUserInfoToStorage = function(info) {
498
+ var saveUserInfoToStorage = useCallback(function(info) {
479
499
  try {
480
500
  window.localStorage.setItem(userInfoStorageKey, JSON.stringify(info));
481
501
  } catch (err) {
482
502
  console.error("儲存 userInfo 失敗:", err);
483
503
  }
484
- };
504
+ }, [
505
+ userInfoStorageKey
506
+ ]);
507
+ // 儲存 LIFF profile 到 localStorage
508
+ var saveLiffProfileToStorage = useCallback(function(info) {
509
+ try {
510
+ window.localStorage.setItem(liffProfileStorageKey, JSON.stringify(info));
511
+ } catch (err) {
512
+ console.error("儲存 liffProfile 失敗:", err);
513
+ }
514
+ }, [
515
+ liffProfileStorageKey
516
+ ]);
517
+ // 儲存 liffInitialized flag 到 localStorage
518
+ var saveLiffInitializedToStorage = useCallback(function() {
519
+ try {
520
+ window.localStorage.setItem(liffInitializedStorageKey, "1");
521
+ } catch (err) {
522
+ console.error("儲存 liffInitialized 失敗:", err);
523
+ }
524
+ }, [
525
+ liffInitializedStorageKey
526
+ ]);
485
527
  var fetchMemberInfo = function() {
486
528
  var _ref = _async_to_generator(function(token) {
487
529
  var response, err;
@@ -590,6 +632,13 @@ var LiffProvider = function(param) {
590
632
  // token 無效時清除 userInfo
591
633
  setUserInfo(null);
592
634
  window.localStorage.removeItem(userInfoStorageKey);
635
+ // token 無效也清除 liff 相關快取與已初始化標記
636
+ try {
637
+ window.localStorage.removeItem(liffProfileStorageKey);
638
+ window.localStorage.removeItem(liffInitializedStorageKey);
639
+ } catch (e) {
640
+ // ignore
641
+ }
593
642
  return [
594
643
  3,
595
644
  7
@@ -699,41 +748,37 @@ var LiffProvider = function(param) {
699
748
  // 初始化 LIFF
700
749
  var initializeLiff = function() {
701
750
  var _ref = _async_to_generator(function(isValid) {
702
- var customFetch, liff, originalFetch, lineToken, redirectUri, e, tempFriendship, friendship, friendFlag, error, err;
751
+ var _sdk_getAccessToken, _sdk_isLoggedIn, imported, sdk, lineToken, redirectUri, tempFriendship, friendship, friendFlag, error, err;
703
752
  return _ts_generator(this, function(_state) {
704
753
  switch(_state.label){
705
754
  case 0:
706
755
  _state.trys.push([
707
756
  0,
708
- 16,
757
+ 10,
709
758
  ,
710
- 17
759
+ 11
711
760
  ]);
712
- customFetch = // 自訂 fetch 函數,避免每次請求都改變 URL
713
- // eslint-disable-next-line no-inner-declarations
714
- function customFetch(url, options) {
715
- if (url.toString().startsWith("https://liffsdk.line-scdn.net/xlt/") && url.toString().endsWith(".json")) {
716
- url = "".concat(url, "?ts=").concat(Math.random());
717
- }
718
- return originalFetch(url, options);
719
- };
761
+ // 確保 LIFF 已初始化(只執行一次)
720
762
  return [
721
763
  4,
722
- import('./index.esm3.js')
764
+ ensureLiffInitialized()
723
765
  ];
724
766
  case 1:
725
- liff = _state.sent().liff;
726
- originalFetch = window.fetch;
727
- window.fetch = customFetch;
728
- if (openInApp && !(liff === null || liff === void 0 ? void 0 : liff.isInClient()) && (liff === null || liff === void 0 ? void 0 : liff.getOS()) !== "web") window.location.href = "line://app/".concat(liffId);
729
- console.log("LIFF init succeeded.");
730
- setLiffObject(liff);
731
- lineToken = liff === null || liff === void 0 ? void 0 : liff.getAccessToken();
732
- // 未登入先進行登入(呼叫 login 後立即 return,避免後續執行 init)
733
- if (!liff.isLoggedIn()) {
767
+ _state.sent();
768
+ return [
769
+ 4,
770
+ import('./index.esm3.js')
771
+ ];
772
+ case 2:
773
+ imported = _state.sent();
774
+ sdk = liffObject || imported.liff;
775
+ setLiffObject(sdk);
776
+ lineToken = sdk === null || sdk === void 0 ? void 0 : (_sdk_getAccessToken = sdk.getAccessToken) === null || _sdk_getAccessToken === void 0 ? void 0 : _sdk_getAccessToken.call(sdk);
777
+ // 未登入先進行登入(呼叫 login 後立即 return,避免後續執行)
778
+ if (!(sdk === null || sdk === void 0 ? void 0 : (_sdk_isLoggedIn = sdk.isLoggedIn) === null || _sdk_isLoggedIn === void 0 ? void 0 : _sdk_isLoggedIn.call(sdk))) {
734
779
  redirectUri = customerRedirectUrl || "".concat(window.location.href);
735
780
  if (liffLogin) {
736
- liff.login({
781
+ sdk.login({
737
782
  redirectUri: redirectUri
738
783
  });
739
784
  return [
@@ -743,105 +788,54 @@ var LiffProvider = function(param) {
743
788
  if (loginByUser || ignoreRoute) return [
744
789
  2
745
790
  ];
746
- liff.login({
791
+ sdk.login({
747
792
  redirectUri: redirectUri
748
793
  });
749
794
  return [
750
795
  2
751
796
  ];
752
797
  }
753
- if (!!liffId) return [
754
- 3,
755
- 2
756
- ];
757
- console.warn("liffId 未提供,跳過 liff.init()。");
758
- return [
759
- 3,
760
- 8
761
- ];
762
- case 2:
763
- if (!!liff.isLoggedIn()) return [
798
+ tempFriendship = null;
799
+ if (!lineToken) return [
764
800
  3,
765
- 7
801
+ 9
766
802
  ];
767
803
  _state.label = 3;
768
804
  case 3:
769
805
  _state.trys.push([
770
806
  3,
771
- 5,
772
- ,
773
- 6
774
- ]);
775
- return [
776
- 4,
777
- liff.init({
778
- liffId: liffId,
779
- withLoginOnExternalBrowser: false
780
- })
781
- ];
782
- case 4:
783
- _state.sent();
784
- return [
785
- 3,
786
- 6
787
- ];
788
- case 5:
789
- e = _state.sent();
790
- console.error("liff.init() 失敗:", e);
791
- return [
792
- 3,
793
- 6
794
- ];
795
- case 6:
796
- return [
797
- 3,
798
- 8
799
- ];
800
- case 7:
801
- console.log("LIFF 已登入,跳過 liff.init() 以避免重複的 verify/profile 呼叫。");
802
- _state.label = 8;
803
- case 8:
804
- tempFriendship = null;
805
- if (!lineToken) return [
806
- 3,
807
- 15
808
- ];
809
- _state.label = 9;
810
- case 9:
811
- _state.trys.push([
812
- 9,
813
- 12,
807
+ 6,
814
808
  ,
815
- 13
809
+ 7
816
810
  ]);
817
- if (!!liff.isLoggedIn()) return [
811
+ if (!(sdk.isLoggedIn && sdk.isLoggedIn())) return [
818
812
  3,
819
- 11
813
+ 5
820
814
  ];
821
815
  return [
822
816
  4,
823
- liff.getFriendship()
817
+ sdk.getFriendship()
824
818
  ];
825
- case 10:
819
+ case 4:
826
820
  friendship = _state.sent();
827
821
  friendFlag = friendship === null || friendship === void 0 ? void 0 : friendship.friendFlag;
828
822
  setFriendship(friendFlag);
829
823
  tempFriendship = friendFlag;
830
824
  console.log("isFriendship", friendFlag);
831
- _state.label = 11;
832
- case 11:
825
+ _state.label = 5;
826
+ case 5:
833
827
  return [
834
828
  3,
835
- 13
829
+ 7
836
830
  ];
837
- case 12:
831
+ case 6:
838
832
  error = _state.sent();
839
833
  console.error("Error in liff.getFriendship():", error);
840
834
  return [
841
835
  3,
842
- 13
836
+ 7
843
837
  ];
844
- case 13:
838
+ case 7:
845
839
  console.log("isValid", isValid);
846
840
  if (tempFriendship && isValid) return [
847
841
  2
@@ -850,23 +844,23 @@ var LiffProvider = function(param) {
850
844
  4,
851
845
  loginInit(lineToken)
852
846
  ];
853
- case 14:
847
+ case 8:
854
848
  _state.sent();
855
- _state.label = 15;
856
- case 15:
849
+ _state.label = 9;
850
+ case 9:
857
851
  return [
858
852
  3,
859
- 17
853
+ 11
860
854
  ];
861
- case 16:
855
+ case 10:
862
856
  err = _state.sent();
863
857
  setLiffError(err.toString());
864
858
  console.log("LIFF init failed.", err);
865
859
  return [
866
860
  3,
867
- 17
861
+ 11
868
862
  ];
869
- case 17:
863
+ case 11:
870
864
  return [
871
865
  2
872
866
  ];
@@ -877,6 +871,125 @@ var LiffProvider = function(param) {
877
871
  return _ref.apply(this, arguments);
878
872
  };
879
873
  }();
874
+ // 確保 LIFF init 只執行一次且在需要時才執行
875
+ var ensureLiffInitialized = useCallback(/*#__PURE__*/ _async_to_generator(function() {
876
+ var storedFlag, customFetch, liff, originalFetch, profile, e1;
877
+ return _ts_generator(this, function(_state) {
878
+ switch(_state.label){
879
+ case 0:
880
+ console.log("ensureLiffInitialized called", liffInitialized);
881
+ // 如果 state 或 localStorage 上已有 initialized 的標記,就視為已初始化
882
+ if (liffInitialized) return [
883
+ 2
884
+ ];
885
+ try {
886
+ storedFlag = window.localStorage.getItem(liffInitializedStorageKey);
887
+ if (storedFlag === "1") {
888
+ setLiffInitialized(true);
889
+ console.log("liffInitialized loaded from storage");
890
+ return [
891
+ 2
892
+ ];
893
+ }
894
+ } catch (e) {
895
+ // ignore
896
+ }
897
+ if (!liffId) {
898
+ console.warn("liffId 未提供,跳過 liff.init()。");
899
+ return [
900
+ 2
901
+ ];
902
+ }
903
+ _state.label = 1;
904
+ case 1:
905
+ _state.trys.push([
906
+ 1,
907
+ 8,
908
+ ,
909
+ 9
910
+ ]);
911
+ customFetch = // 自訂 fetch 函數,避免每次請求都改變 URL
912
+ // eslint-disable-next-line no-inner-declarations
913
+ function customFetch(url, options) {
914
+ if (url.toString().startsWith("https://liffsdk.line-scdn.net/xlt/") && url.toString().endsWith(".json")) {
915
+ url = "".concat(url, "?ts=").concat(Math.random());
916
+ }
917
+ return originalFetch(url, options);
918
+ };
919
+ return [
920
+ 4,
921
+ import('./index.esm3.js')
922
+ ];
923
+ case 2:
924
+ liff = _state.sent().liff;
925
+ originalFetch = window.fetch;
926
+ window.fetch = customFetch;
927
+ if (openInApp && !(liff === null || liff === void 0 ? void 0 : liff.isInClient()) && (liff === null || liff === void 0 ? void 0 : liff.getOS()) !== "web") window.location.href = "line://app/".concat(liffId);
928
+ return [
929
+ 4,
930
+ liff.init({
931
+ liffId: liffId,
932
+ withLoginOnExternalBrowser: false
933
+ })
934
+ ];
935
+ case 3:
936
+ _state.sent();
937
+ _state.label = 4;
938
+ case 4:
939
+ _state.trys.push([
940
+ 4,
941
+ 6,
942
+ ,
943
+ 7
944
+ ]);
945
+ return [
946
+ 4,
947
+ liff.getProfile()
948
+ ];
949
+ case 5:
950
+ profile = _state.sent();
951
+ setLiffProfile(profile);
952
+ saveLiffProfileToStorage(profile);
953
+ return [
954
+ 3,
955
+ 7
956
+ ];
957
+ case 6:
958
+ _state.sent();
959
+ return [
960
+ 3,
961
+ 7
962
+ ];
963
+ case 7:
964
+ setLiffObject(liff);
965
+ setLiffInitialized(true);
966
+ saveLiffInitializedToStorage();
967
+ console.log("LIFF initialized.");
968
+ return [
969
+ 3,
970
+ 9
971
+ ];
972
+ case 8:
973
+ e1 = _state.sent();
974
+ console.error("ensureLiffInitialized failed:", e1);
975
+ return [
976
+ 3,
977
+ 9
978
+ ];
979
+ case 9:
980
+ return [
981
+ 2
982
+ ];
983
+ }
984
+ });
985
+ }), [
986
+ liffInitialized,
987
+ liffId,
988
+ openInApp,
989
+ saveLiffInitializedToStorage,
990
+ saveLiffProfileToStorage,
991
+ liffInitializedStorageKey
992
+ ]);
880
993
  var accountLogin = function() {
881
994
  var _ref = _async_to_generator(function(username, password) {
882
995
  var response, token, tokenType, finalToken, err;
@@ -1043,9 +1156,10 @@ var LiffProvider = function(param) {
1043
1156
  return trimmed.toLowerCase().startsWith("bearer ") ? trimmed : "Bearer ".concat(trimmed);
1044
1157
  };
1045
1158
  var searchParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
1046
- // 初始載入時從 localStorage 載入 userInfo
1159
+ // 初始載入時從 localStorage 載入 userInfo 與 LIFF profile
1047
1160
  useEffect(function() {
1048
1161
  loadUserInfoFromStorage();
1162
+ loadLiffProfileFromStorage();
1049
1163
  }, []);
1050
1164
  // 客戶端初始化 LIFF
1051
1165
  useEffect(function() {
@@ -1123,32 +1237,21 @@ var LiffProvider = function(param) {
1123
1237
  }();
1124
1238
  checkAndInitialize();
1125
1239
  }, []);
1126
- var contextValue = useMemo(function() {
1127
- return {
1128
- liffObject: liffObject,
1129
- loginData: loginData,
1130
- userInfo: userInfo,
1131
- accessToken: accessToken,
1132
- liffError: liffError,
1133
- initializeLiff: function() {
1134
- return initializeLiff(false);
1135
- },
1136
- isFriendship: isFriendship,
1137
- ensureLiffTokenValid: ensureLiffTokenValid,
1138
- accountLogin: accountLogin,
1139
- loginType: loginType
1140
- };
1141
- }, [
1142
- liffObject,
1143
- loginData,
1144
- userInfo,
1145
- accessToken,
1146
- liffError,
1147
- isFriendship,
1148
- ensureLiffTokenValid,
1149
- accountLogin,
1150
- loginType
1151
- ]);
1240
+ var contextValue = {
1241
+ liffObject: liffObject,
1242
+ loginData: loginData,
1243
+ userInfo: userInfo,
1244
+ accessToken: accessToken,
1245
+ liffError: liffError,
1246
+ initializeLiff: function() {
1247
+ return initializeLiff(false);
1248
+ },
1249
+ liffProfile: liffProfile,
1250
+ isFriendship: isFriendship,
1251
+ ensureLiffTokenValid: ensureLiffTokenValid,
1252
+ accountLogin: accountLogin,
1253
+ loginType: loginType
1254
+ };
1152
1255
  return /*#__PURE__*/ jsx(LiffContext.Provider, {
1153
1256
  value: contextValue,
1154
1257
  children: children
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunggang/ui-lib",
3
- "version": "0.4.43",
3
+ "version": "0.4.45",
4
4
  "sideEffects": [
5
5
  "*.css",
6
6
  "./src/style.css",
@@ -3,6 +3,7 @@ type LiffContextType = {
3
3
  liffObject: any;
4
4
  loginData: any;
5
5
  userInfo?: any;
6
+ liffProfile?: any;
6
7
  accessToken: string;
7
8
  liffError: string | null;
8
9
  initializeLiff: () => Promise<void>;