academe-kit 0.5.8 → 0.6.1
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.
- package/dist/index.cjs +173 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +65 -0
- package/dist/index.esm.js +173 -122
- package/dist/index.esm.js.map +1 -1
- package/dist/types/context/SecurityProvider/types.d.ts +6 -3
- package/dist/types/services/StorageFileService.d.ts +61 -0
- package/dist/types/services/index.d.ts +3 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5772,6 +5772,54 @@ function createCourseService(apiClient) {
|
|
|
5772
5772
|
};
|
|
5773
5773
|
}
|
|
5774
5774
|
|
|
5775
|
+
function createStorageFileService(apiClient) {
|
|
5776
|
+
return {
|
|
5777
|
+
/**
|
|
5778
|
+
* Upload a new file
|
|
5779
|
+
* Note: This method requires FormData with a 'file' field
|
|
5780
|
+
*/
|
|
5781
|
+
upload(file) {
|
|
5782
|
+
const formData = new FormData();
|
|
5783
|
+
formData.append("file", file);
|
|
5784
|
+
// Note: Route not typed in OpenAPI yet, using type assertion
|
|
5785
|
+
return apiClient.POST("/storage-files", {
|
|
5786
|
+
body: formData,
|
|
5787
|
+
bodySerializer: (body) => body,
|
|
5788
|
+
});
|
|
5789
|
+
},
|
|
5790
|
+
/**
|
|
5791
|
+
* List all storage files
|
|
5792
|
+
*/
|
|
5793
|
+
getAll() {
|
|
5794
|
+
// Note: Route not typed in OpenAPI yet, using type assertion
|
|
5795
|
+
return apiClient.GET("/storage-files", {});
|
|
5796
|
+
},
|
|
5797
|
+
/**
|
|
5798
|
+
* Get storage file by ID
|
|
5799
|
+
*/
|
|
5800
|
+
getById(id) {
|
|
5801
|
+
// Note: Route not typed in OpenAPI yet, using type assertion
|
|
5802
|
+
return apiClient.GET(`/storage-files/${id}`, {});
|
|
5803
|
+
},
|
|
5804
|
+
/**
|
|
5805
|
+
* Update storage file metadata
|
|
5806
|
+
*/
|
|
5807
|
+
update(id, data) {
|
|
5808
|
+
// Note: Route not typed in OpenAPI yet, using type assertion
|
|
5809
|
+
return apiClient.PATCH(`/storage-files/${id}`, {
|
|
5810
|
+
body: data,
|
|
5811
|
+
});
|
|
5812
|
+
},
|
|
5813
|
+
/**
|
|
5814
|
+
* Delete storage file
|
|
5815
|
+
*/
|
|
5816
|
+
delete(id) {
|
|
5817
|
+
// Note: Route not typed in OpenAPI yet, using type assertion
|
|
5818
|
+
return apiClient.DELETE(`/storage-files/${id}`, {});
|
|
5819
|
+
},
|
|
5820
|
+
};
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5775
5823
|
function createAcademeApiClient(baseUrl) {
|
|
5776
5824
|
return createClient({ baseUrl });
|
|
5777
5825
|
}
|
|
@@ -5793,6 +5841,7 @@ function createAcademeServices(apiClient) {
|
|
|
5793
5841
|
certificateTemplate: createCertificateTemplateService(apiClient),
|
|
5794
5842
|
seatCode: createSeatCodeService(apiClient),
|
|
5795
5843
|
product: createProductService(apiClient),
|
|
5844
|
+
storageFile: createStorageFileService(apiClient),
|
|
5796
5845
|
};
|
|
5797
5846
|
}
|
|
5798
5847
|
|
|
@@ -5823,6 +5872,7 @@ const AcademeAuthProvider = ({ realm, hubUrl, children, clientId, keycloakUrl, a
|
|
|
5823
5872
|
const SecurityContext = React2.createContext({
|
|
5824
5873
|
isInitialized: false,
|
|
5825
5874
|
isTokenReady: false,
|
|
5875
|
+
isMobileAuth: false,
|
|
5826
5876
|
user: null,
|
|
5827
5877
|
refreshUserData: async () => { },
|
|
5828
5878
|
signOut: () => null,
|
|
@@ -5852,119 +5902,70 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
5852
5902
|
const [currentUser, setCurrentUser] = React2.useState(null);
|
|
5853
5903
|
const hasTriedSignInSilent = React2.useRef(false);
|
|
5854
5904
|
const [isTokenReady, setIsTokenReady] = React2.useState(false);
|
|
5905
|
+
const [isRefreshing, setIsRefreshing] = React2.useState(false);
|
|
5906
|
+
// --- Estado para autenticação mobile ---
|
|
5907
|
+
const [isMobileAuth, setIsMobileAuth] = React2.useState(false);
|
|
5908
|
+
const [mobileToken, setMobileToken] = React2.useState(undefined);
|
|
5909
|
+
const mobileInitializedRef = React2.useRef(false);
|
|
5855
5910
|
// Ref para armazenar o resolver da Promise de token
|
|
5856
5911
|
const tokenReadyResolverRef = React2.useRef(null);
|
|
5857
5912
|
const tokenReadyPromiseRef = React2.useRef(null);
|
|
5858
|
-
// Estados para controle de token injetado pelo mobile
|
|
5859
|
-
const [mobileToken, setMobileToken] = React2.useState(undefined);
|
|
5860
|
-
const [isMobileWebView, setIsMobileWebView] = React2.useState(false);
|
|
5861
|
-
const [isMobileDetectionComplete, setIsMobileDetectionComplete] = React2.useState(false);
|
|
5862
5913
|
// Extrair valores primitivos do auth para usar como dependências estáveis
|
|
5863
5914
|
const isAuthenticated = auth.isAuthenticated;
|
|
5864
5915
|
const isLoading = auth.isLoading;
|
|
5865
5916
|
const activeNavigator = auth.activeNavigator;
|
|
5866
|
-
const
|
|
5917
|
+
const accessToken = auth.user?.access_token;
|
|
5867
5918
|
const userProfile = auth.user?.profile;
|
|
5868
5919
|
const userProfileSub = auth.user?.profile?.sub;
|
|
5869
|
-
//
|
|
5870
|
-
const
|
|
5871
|
-
// --- 0.
|
|
5920
|
+
// Ref para armazenar o token atual (acessível no middleware)
|
|
5921
|
+
const currentTokenRef = React2.useRef(undefined);
|
|
5922
|
+
// --- 0. Detecção de Token Mobile (ANTES do SSO check) ---
|
|
5872
5923
|
React2.useEffect(() => {
|
|
5924
|
+
// Só executa uma vez na inicialização
|
|
5925
|
+
if (mobileInitializedRef.current)
|
|
5926
|
+
return;
|
|
5927
|
+
mobileInitializedRef.current = true;
|
|
5873
5928
|
if (typeof window === "undefined")
|
|
5874
5929
|
return;
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
// Verificamos múltiplos indicadores porque no iOS o ReactNativeWebView pode ser injetado depois
|
|
5879
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
5880
|
-
const isEmbedded = urlParams.get('embedded') === 'true';
|
|
5881
|
-
const hasReactNativeWebView = !!window.ReactNativeWebView;
|
|
5882
|
-
const hasKeycloakConfig = !!window.keycloakConfig?.fromMobile;
|
|
5883
|
-
const shouldCheckForMobileToken = isEmbedded || hasReactNativeWebView || hasKeycloakConfig;
|
|
5884
|
-
console.log('[SecurityProvider] Verificação mobile:', {
|
|
5885
|
-
isEmbedded,
|
|
5886
|
-
hasReactNativeWebView,
|
|
5887
|
-
hasKeycloakConfig,
|
|
5888
|
-
shouldCheckForMobileToken
|
|
5889
|
-
});
|
|
5890
|
-
// Se não há indicadores de mobile, completa imediatamente
|
|
5891
|
-
if (!shouldCheckForMobileToken) {
|
|
5892
|
-
console.log('[SecurityProvider] Não é contexto mobile - pulando detecção');
|
|
5893
|
-
setIsMobileDetectionComplete(true);
|
|
5930
|
+
const keycloakConfig = window.keycloakConfig;
|
|
5931
|
+
if (!keycloakConfig?.fromMobile || !keycloakConfig?.token) {
|
|
5932
|
+
console.debug("[SecurityProvider] Modo web normal - sem token mobile");
|
|
5894
5933
|
return;
|
|
5895
5934
|
}
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
const checkAndSetMobileToken = () => {
|
|
5902
|
-
if (window.keycloakConfig?.fromMobile && window.keycloakConfig?.token) {
|
|
5903
|
-
console.log('[SecurityProvider] Token mobile detectado');
|
|
5904
|
-
setIsMobileWebView(true);
|
|
5905
|
-
setMobileToken(window.keycloakConfig.token);
|
|
5906
|
-
setIsMobileDetectionComplete(true);
|
|
5907
|
-
return true;
|
|
5908
|
-
}
|
|
5909
|
-
return false;
|
|
5910
|
-
};
|
|
5911
|
-
// 1. Verificação imediata
|
|
5912
|
-
if (checkAndSetMobileToken()) {
|
|
5913
|
-
console.log('[SecurityProvider] Token encontrado na verificação inicial');
|
|
5935
|
+
// Validar e decodificar o token mobile
|
|
5936
|
+
const decoded = decodeAccessToken(keycloakConfig.token);
|
|
5937
|
+
if (!decoded) {
|
|
5938
|
+
console.error("[SecurityProvider] Token mobile inválido - ignorando");
|
|
5939
|
+
return;
|
|
5914
5940
|
}
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
console.log(`[SecurityProvider] Token encontrado após ${pollingAttempts} tentativas (${pollingAttempts * POLLING_INTERVAL_MS}ms)`);
|
|
5921
|
-
if (pollingInterval) {
|
|
5922
|
-
clearInterval(pollingInterval);
|
|
5923
|
-
pollingInterval = null;
|
|
5924
|
-
}
|
|
5925
|
-
}
|
|
5926
|
-
else if (pollingAttempts >= MAX_POLLING_ATTEMPTS) {
|
|
5927
|
-
console.log('[SecurityProvider] Polling encerrado - token não encontrado após 3 segundos');
|
|
5928
|
-
setIsMobileDetectionComplete(true);
|
|
5929
|
-
if (pollingInterval) {
|
|
5930
|
-
clearInterval(pollingInterval);
|
|
5931
|
-
pollingInterval = null;
|
|
5932
|
-
}
|
|
5933
|
-
}
|
|
5934
|
-
}, POLLING_INTERVAL_MS);
|
|
5941
|
+
// Verificar se o token não está expirado
|
|
5942
|
+
const now = Math.floor(Date.now() / 1000);
|
|
5943
|
+
if (decoded.exp && decoded.exp < now) {
|
|
5944
|
+
console.error("[SecurityProvider] Token mobile expirado - ignorando");
|
|
5945
|
+
return;
|
|
5935
5946
|
}
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
console.log('[SecurityProvider] Token atualizado via evento keycloakTokenRefreshed');
|
|
5951
|
-
setMobileToken(event.detail.token);
|
|
5952
|
-
};
|
|
5953
|
-
window.addEventListener("keycloakConfigInjected", handleInjection);
|
|
5954
|
-
window.addEventListener("keycloakTokenRefreshed", handleTokenRefresh);
|
|
5955
|
-
return () => {
|
|
5956
|
-
if (pollingInterval) {
|
|
5957
|
-
clearInterval(pollingInterval);
|
|
5958
|
-
}
|
|
5959
|
-
window.removeEventListener("keycloakConfigInjected", handleInjection);
|
|
5960
|
-
window.removeEventListener("keycloakTokenRefreshed", handleTokenRefresh);
|
|
5961
|
-
};
|
|
5947
|
+
console.log("[SecurityProvider] ✅ Token mobile detectado e válido");
|
|
5948
|
+
// Ativar modo mobile
|
|
5949
|
+
setMobileToken(keycloakConfig.token);
|
|
5950
|
+
setIsMobileAuth(true);
|
|
5951
|
+
// Sincronizar com window.accessToken e currentTokenRef
|
|
5952
|
+
window.accessToken = keycloakConfig.token;
|
|
5953
|
+
currentTokenRef.current = keycloakConfig.token;
|
|
5954
|
+
// Marcar que já tentamos SSO (para pular o check)
|
|
5955
|
+
hasTriedSignInSilent.current = true;
|
|
5956
|
+
// Resolver promise de token imediatamente
|
|
5957
|
+
if (tokenReadyResolverRef.current) {
|
|
5958
|
+
tokenReadyResolverRef.current();
|
|
5959
|
+
}
|
|
5960
|
+
setIsTokenReady(true);
|
|
5962
5961
|
}, []);
|
|
5963
|
-
// --- 1. Silent Check Inicial (Check SSO) ---
|
|
5962
|
+
// --- 1. Silent Check Inicial (Check SSO) - Pulado se mobile ---
|
|
5964
5963
|
React2.useEffect(() => {
|
|
5965
|
-
//
|
|
5966
|
-
if (
|
|
5964
|
+
// Pular SSO check se já estamos em modo mobile
|
|
5965
|
+
if (isMobileAuth) {
|
|
5966
|
+
console.debug("[SecurityProvider] Modo mobile - pulando SSO check");
|
|
5967
5967
|
return;
|
|
5968
|
+
}
|
|
5968
5969
|
if (!isAuthenticated &&
|
|
5969
5970
|
!isLoading &&
|
|
5970
5971
|
!activeNavigator &&
|
|
@@ -5975,10 +5976,8 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
5975
5976
|
});
|
|
5976
5977
|
}
|
|
5977
5978
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5978
|
-
}, [isAuthenticated, isLoading, activeNavigator,
|
|
5979
|
+
}, [isAuthenticated, isLoading, activeNavigator, isMobileAuth]);
|
|
5979
5980
|
// --- 2. Configuração de API e Services ---
|
|
5980
|
-
// Ref para armazenar o token atual (acessível no middleware)
|
|
5981
|
-
const currentTokenRef = React2.useRef(undefined);
|
|
5982
5981
|
const apiClient = React2.useMemo(() => {
|
|
5983
5982
|
const client = createAcademeApiClient(apiBaseUrl);
|
|
5984
5983
|
// Inicializa a Promise de token ready
|
|
@@ -6008,11 +6007,18 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6008
6007
|
const services = React2.useMemo(() => {
|
|
6009
6008
|
return createAcademeServices(apiClient);
|
|
6010
6009
|
}, [apiClient]);
|
|
6010
|
+
// Token efetivo: prioriza mobile, depois OIDC
|
|
6011
|
+
const effectiveToken = mobileToken || accessToken;
|
|
6011
6012
|
const decodedAccessToken = React2.useMemo(() => {
|
|
6012
|
-
return
|
|
6013
|
-
}, [
|
|
6013
|
+
return effectiveToken ? decodeAccessToken(effectiveToken) : null;
|
|
6014
|
+
}, [effectiveToken]);
|
|
6014
6015
|
// Atualização do Token e resolução da Promise
|
|
6016
|
+
// Não sobrescreve se estamos em modo mobile
|
|
6015
6017
|
React2.useEffect(() => {
|
|
6018
|
+
// Se estamos em modo mobile, o token já foi configurado
|
|
6019
|
+
if (isMobileAuth) {
|
|
6020
|
+
return;
|
|
6021
|
+
}
|
|
6016
6022
|
currentTokenRef.current = accessToken;
|
|
6017
6023
|
if (typeof window !== "undefined") {
|
|
6018
6024
|
window.accessToken = accessToken;
|
|
@@ -6031,16 +6037,26 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6031
6037
|
setIsTokenReady(true);
|
|
6032
6038
|
}
|
|
6033
6039
|
}
|
|
6034
|
-
}, [accessToken, isLoading, isAuthenticated]);
|
|
6040
|
+
}, [accessToken, isLoading, isAuthenticated, isMobileAuth]);
|
|
6035
6041
|
// --- 3. Helpers de Usuário e Roles ---
|
|
6036
6042
|
const getKeycloakUser = React2.useCallback(() => {
|
|
6043
|
+
// Se estamos em modo mobile, extrair do token decodificado
|
|
6044
|
+
if (isMobileAuth && decodedAccessToken) {
|
|
6045
|
+
return {
|
|
6046
|
+
email: decodedAccessToken.email || "",
|
|
6047
|
+
name: decodedAccessToken.given_name || "",
|
|
6048
|
+
lastName: decodedAccessToken.family_name || "",
|
|
6049
|
+
};
|
|
6050
|
+
}
|
|
6051
|
+
// Modo OIDC normal
|
|
6037
6052
|
const profile = userProfile;
|
|
6038
6053
|
return {
|
|
6039
6054
|
email: profile?.email || "",
|
|
6040
6055
|
name: profile?.given_name || "",
|
|
6041
6056
|
lastName: profile?.family_name || "",
|
|
6057
|
+
avatar_url: decodedAccessToken?.avatar_url
|
|
6042
6058
|
};
|
|
6043
|
-
}, [userProfile]);
|
|
6059
|
+
}, [userProfile, isMobileAuth, decodedAccessToken]);
|
|
6044
6060
|
const hasRealmRole = React2.useCallback((role) => {
|
|
6045
6061
|
return decodedAccessToken?.realm_access?.roles?.includes(role) ?? false;
|
|
6046
6062
|
}, [decodedAccessToken]);
|
|
@@ -6055,17 +6071,20 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6055
6071
|
}
|
|
6056
6072
|
return Object.values(decodedAccessToken.resource_access).some((resource) => resource.roles?.includes(role));
|
|
6057
6073
|
}, [decodedAccessToken]);
|
|
6074
|
+
// Autenticação efetiva: mobile ou OIDC
|
|
6075
|
+
const effectiveIsAuthenticated = isMobileAuth || isAuthenticated;
|
|
6076
|
+
const effectiveUserSub = isMobileAuth ? decodedAccessToken?.sub : userProfileSub;
|
|
6058
6077
|
// --- 4. Fetch de Dados do Usuário (Backend) ---
|
|
6059
6078
|
React2.useEffect(() => {
|
|
6060
6079
|
let isMounted = true;
|
|
6061
6080
|
const fetchUserData = async () => {
|
|
6062
|
-
if (
|
|
6081
|
+
if (effectiveIsAuthenticated) {
|
|
6063
6082
|
if (skipApiUserFetch) {
|
|
6064
6083
|
if (isMounted) {
|
|
6065
6084
|
const academeUser = {
|
|
6066
6085
|
keycloakUser: getKeycloakUser(),
|
|
6067
6086
|
};
|
|
6068
|
-
setCurrentUser({ ...academeUser, id:
|
|
6087
|
+
setCurrentUser({ ...academeUser, id: effectiveUserSub || "" });
|
|
6069
6088
|
}
|
|
6070
6089
|
return;
|
|
6071
6090
|
}
|
|
@@ -6083,7 +6102,7 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6083
6102
|
console.error("[SecurityProvider] Error fetching user data:", error);
|
|
6084
6103
|
}
|
|
6085
6104
|
}
|
|
6086
|
-
else if (!
|
|
6105
|
+
else if (!effectiveIsAuthenticated && !isLoading && !isMobileAuth) {
|
|
6087
6106
|
if (isMounted) {
|
|
6088
6107
|
setCurrentUser(null);
|
|
6089
6108
|
}
|
|
@@ -6094,16 +6113,19 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6094
6113
|
isMounted = false;
|
|
6095
6114
|
};
|
|
6096
6115
|
}, [
|
|
6097
|
-
|
|
6116
|
+
effectiveIsAuthenticated,
|
|
6098
6117
|
isLoading,
|
|
6099
6118
|
getKeycloakUser,
|
|
6100
6119
|
services,
|
|
6101
6120
|
skipApiUserFetch,
|
|
6102
|
-
|
|
6121
|
+
effectiveUserSub,
|
|
6122
|
+
isMobileAuth,
|
|
6103
6123
|
]);
|
|
6104
6124
|
const refreshUserData = React2.useCallback(async () => {
|
|
6105
|
-
|
|
6125
|
+
setIsRefreshing(true);
|
|
6126
|
+
if (effectiveIsAuthenticated) {
|
|
6106
6127
|
if (skipApiUserFetch) {
|
|
6128
|
+
await auth.signinSilent();
|
|
6107
6129
|
const academeUser = {
|
|
6108
6130
|
keycloakUser: getKeycloakUser(),
|
|
6109
6131
|
};
|
|
@@ -6124,10 +6146,12 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6124
6146
|
console.error("[SecurityProvider] Error refreshing user data:", error);
|
|
6125
6147
|
}
|
|
6126
6148
|
}
|
|
6127
|
-
|
|
6149
|
+
setIsRefreshing(false);
|
|
6150
|
+
}, [effectiveIsAuthenticated, getKeycloakUser, services, skipApiUserFetch]);
|
|
6128
6151
|
// --- 5. Ações de Auth ---
|
|
6129
|
-
|
|
6130
|
-
|
|
6152
|
+
// SignOut para modo OIDC (web normal)
|
|
6153
|
+
const signOutOidc = React2.useCallback(() => {
|
|
6154
|
+
console.log("[KC LOGOUT - OIDC]");
|
|
6131
6155
|
setCurrentUser(null);
|
|
6132
6156
|
auth.removeUser();
|
|
6133
6157
|
auth.signoutRedirect({
|
|
@@ -6135,6 +6159,32 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6135
6159
|
});
|
|
6136
6160
|
auth.clearStaleState();
|
|
6137
6161
|
}, [auth]);
|
|
6162
|
+
// SignOut para modo mobile
|
|
6163
|
+
const signOutMobile = React2.useCallback(() => {
|
|
6164
|
+
console.log("[KC LOGOUT - Mobile]");
|
|
6165
|
+
setCurrentUser(null);
|
|
6166
|
+
setMobileToken(undefined);
|
|
6167
|
+
setIsMobileAuth(false);
|
|
6168
|
+
// Limpar tokens globais
|
|
6169
|
+
if (typeof window !== "undefined") {
|
|
6170
|
+
window.accessToken = undefined;
|
|
6171
|
+
window.keycloakConfig = undefined;
|
|
6172
|
+
}
|
|
6173
|
+
currentTokenRef.current = undefined;
|
|
6174
|
+
// Notificar o app mobile para fazer logout
|
|
6175
|
+
if (window.ReactNativeWebView) {
|
|
6176
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: "LOGOUT_REQUESTED" }));
|
|
6177
|
+
}
|
|
6178
|
+
}, []);
|
|
6179
|
+
// SignOut unificado: escolhe automaticamente baseado no modo
|
|
6180
|
+
const signOut = React2.useCallback(() => {
|
|
6181
|
+
if (isMobileAuth) {
|
|
6182
|
+
signOutMobile();
|
|
6183
|
+
}
|
|
6184
|
+
else {
|
|
6185
|
+
signOutOidc();
|
|
6186
|
+
}
|
|
6187
|
+
}, [isMobileAuth, signOutMobile, signOutOidc]);
|
|
6138
6188
|
const hasSchool = React2.useCallback((schoolId) => {
|
|
6139
6189
|
if (hasRealmRole(exports.GLOBAL_ROLES.ADMIN_ACADEME)) {
|
|
6140
6190
|
return true;
|
|
@@ -6142,44 +6192,45 @@ const SecurityProvider = ({ apiBaseUrl = "https://stg-api.academe.com.br", skipA
|
|
|
6142
6192
|
return (currentUser?.institutionRegistrations?.some((registration) => registration.institutionId === schoolId) ?? false);
|
|
6143
6193
|
}, [hasRealmRole, currentUser?.institutionRegistrations]);
|
|
6144
6194
|
const goToLogin = React2.useCallback(() => {
|
|
6195
|
+
// Em modo mobile, notificar o app para fazer login
|
|
6196
|
+
if (isMobileAuth && window.ReactNativeWebView) {
|
|
6197
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: "LOGIN_REQUESTED" }));
|
|
6198
|
+
return Promise.resolve();
|
|
6199
|
+
}
|
|
6145
6200
|
return auth.signinRedirect();
|
|
6146
6201
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6147
|
-
}, []);
|
|
6202
|
+
}, [isMobileAuth]);
|
|
6148
6203
|
// Memoizar o value do context para evitar re-renders desnecessários
|
|
6149
|
-
// isInitialized só é true quando:
|
|
6150
|
-
// 1. OIDC terminou de carregar (!isLoading)
|
|
6151
|
-
// 2. E a detecção mobile completou (isMobileDetectionComplete)
|
|
6152
6204
|
const contextValue = React2.useMemo(() => ({
|
|
6153
|
-
isInitialized: !isLoading
|
|
6205
|
+
isInitialized: isMobileAuth ? true : (!isLoading || isRefreshing),
|
|
6154
6206
|
isTokenReady,
|
|
6207
|
+
isMobileAuth,
|
|
6155
6208
|
user: currentUser,
|
|
6156
6209
|
refreshUserData,
|
|
6157
6210
|
signOut,
|
|
6158
|
-
isAuthenticated: () =>
|
|
6211
|
+
isAuthenticated: () => effectiveIsAuthenticated,
|
|
6159
6212
|
hasSchool,
|
|
6160
6213
|
goToLogin,
|
|
6161
6214
|
hasRealmRole,
|
|
6162
6215
|
hasClientRole,
|
|
6163
|
-
accessToken,
|
|
6216
|
+
accessToken: effectiveToken,
|
|
6164
6217
|
apiClient,
|
|
6165
6218
|
services,
|
|
6166
6219
|
}), [
|
|
6220
|
+
isMobileAuth,
|
|
6167
6221
|
isLoading,
|
|
6168
|
-
isMobileDetectionComplete,
|
|
6169
6222
|
isTokenReady,
|
|
6170
6223
|
currentUser,
|
|
6171
6224
|
refreshUserData,
|
|
6172
6225
|
signOut,
|
|
6173
|
-
|
|
6226
|
+
effectiveIsAuthenticated,
|
|
6174
6227
|
hasSchool,
|
|
6175
6228
|
goToLogin,
|
|
6176
6229
|
hasRealmRole,
|
|
6177
6230
|
hasClientRole,
|
|
6178
|
-
|
|
6231
|
+
effectiveToken,
|
|
6179
6232
|
apiClient,
|
|
6180
6233
|
services,
|
|
6181
|
-
isMobileWebView,
|
|
6182
|
-
mobileToken,
|
|
6183
6234
|
]);
|
|
6184
6235
|
return (jsxRuntime.jsx(SecurityContext.Provider, { value: contextValue, children: children }));
|
|
6185
6236
|
};
|