analytica-frontend-lib 1.0.68 → 1.0.70

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.d.mts CHANGED
@@ -26,6 +26,8 @@ export { default as Select, SelectContent, SelectItem, SelectTrigger, SelectValu
26
26
  export { default as Menu, MenuContent, MenuItem, MenuOverflow } from './Menu/index.mjs';
27
27
  export { CardActivitiesResults, CardPerformance, CardProgress, CardQuestions, CardResults, CardSimulado, CardStatus, CardTopic } from './Card/index.mjs';
28
28
  export { Skeleton, SkeletonCard, SkeletonCircle, SkeletonList, SkeletonRectangle, SkeletonRounded, SkeletonTable, SkeletonText } from './Skeleton/index.mjs';
29
+ export { AuthProvider, ProtectedRoute, PublicRoute, useAuth, useAuthGuard, useRouteAuth, withAuth } from './Auth/index.mjs';
30
+ export { default as Tab } from './Tab/index.mjs';
29
31
  import 'react/jsx-runtime';
30
32
  import 'react';
31
33
  import 'zustand';
package/dist/index.d.ts CHANGED
@@ -26,6 +26,8 @@ export { default as Select, SelectContent, SelectItem, SelectTrigger, SelectValu
26
26
  export { default as Menu, MenuContent, MenuItem, MenuOverflow } from './Menu/index.js';
27
27
  export { CardActivitiesResults, CardPerformance, CardProgress, CardQuestions, CardResults, CardSimulado, CardStatus, CardTopic } from './Card/index.js';
28
28
  export { Skeleton, SkeletonCard, SkeletonCircle, SkeletonList, SkeletonRectangle, SkeletonRounded, SkeletonTable, SkeletonText } from './Skeleton/index.js';
29
+ export { AuthProvider, ProtectedRoute, PublicRoute, useAuth, useAuthGuard, useRouteAuth, withAuth } from './Auth/index.js';
30
+ export { default as Tab } from './Tab/index.js';
29
31
  import 'react/jsx-runtime';
30
32
  import 'react';
31
33
  import 'zustand';
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  Alert: () => Alert_default,
24
+ AuthProvider: () => AuthProvider,
24
25
  Badge: () => Badge_default,
25
26
  Button: () => Button_default,
26
27
  Calendar: () => Calendar_default,
@@ -56,6 +57,8 @@ __export(src_exports, {
56
57
  ProfileMenuTrigger: () => ProfileMenuTrigger,
57
58
  ProgressBar: () => ProgressBar_default,
58
59
  ProgressCircle: () => ProgressCircle_default,
60
+ ProtectedRoute: () => ProtectedRoute,
61
+ PublicRoute: () => PublicRoute,
59
62
  Radio: () => Radio_default,
60
63
  Select: () => Select_default,
61
64
  SelectContent: () => SelectContent,
@@ -72,12 +75,17 @@ __export(src_exports, {
72
75
  SkeletonTable: () => SkeletonTable,
73
76
  SkeletonText: () => SkeletonText,
74
77
  Stepper: () => Stepper_default,
78
+ Tab: () => Tab_default,
75
79
  Table: () => Table_default,
76
80
  Text: () => Text_default,
77
81
  TextArea: () => TextArea_default,
78
82
  Toast: () => Toast_default,
79
83
  Toaster: () => Toaster_default,
80
- useToastStore: () => ToastStore_default
84
+ useAuth: () => useAuth,
85
+ useAuthGuard: () => useAuthGuard,
86
+ useRouteAuth: () => useRouteAuth,
87
+ useToastStore: () => ToastStore_default,
88
+ withAuth: () => withAuth
81
89
  });
82
90
  module.exports = __toCommonJS(src_exports);
83
91
 
@@ -5051,9 +5059,308 @@ var SkeletonTable = (0, import_react15.forwardRef)(
5051
5059
  ] });
5052
5060
  }
5053
5061
  );
5062
+
5063
+ // src/components/Auth/Auth.tsx
5064
+ var import_react16 = require("react");
5065
+ var import_react_router_dom = require("react-router-dom");
5066
+ var import_jsx_runtime28 = require("react/jsx-runtime");
5067
+ var AuthContext = (0, import_react16.createContext)(void 0);
5068
+ var AuthProvider = ({
5069
+ children,
5070
+ checkAuthFn,
5071
+ signOutFn,
5072
+ initialAuthState = {},
5073
+ getUserFn,
5074
+ getSessionFn,
5075
+ getTokensFn
5076
+ }) => {
5077
+ const [authState, setAuthState] = (0, import_react16.useState)({
5078
+ isAuthenticated: false,
5079
+ isLoading: true,
5080
+ ...initialAuthState
5081
+ });
5082
+ const checkAuth = (0, import_react16.useCallback)(async () => {
5083
+ try {
5084
+ setAuthState((prev) => ({ ...prev, isLoading: true }));
5085
+ if (!checkAuthFn) {
5086
+ setAuthState((prev) => ({
5087
+ ...prev,
5088
+ isAuthenticated: false,
5089
+ isLoading: false
5090
+ }));
5091
+ return false;
5092
+ }
5093
+ const isAuth = await checkAuthFn();
5094
+ setAuthState((prev) => ({
5095
+ ...prev,
5096
+ isAuthenticated: isAuth,
5097
+ isLoading: false,
5098
+ user: getUserFn ? getUserFn() : prev.user,
5099
+ sessionInfo: getSessionFn ? getSessionFn() : prev.sessionInfo,
5100
+ tokens: getTokensFn ? getTokensFn() : prev.tokens
5101
+ }));
5102
+ return isAuth;
5103
+ } catch (error) {
5104
+ console.error("Erro ao verificar autentica\xE7\xE3o:", error);
5105
+ setAuthState((prev) => ({
5106
+ ...prev,
5107
+ isAuthenticated: false,
5108
+ isLoading: false
5109
+ }));
5110
+ return false;
5111
+ }
5112
+ }, [checkAuthFn, getUserFn, getSessionFn, getTokensFn]);
5113
+ const signOut = (0, import_react16.useCallback)(() => {
5114
+ if (signOutFn) {
5115
+ signOutFn();
5116
+ }
5117
+ setAuthState((prev) => ({
5118
+ ...prev,
5119
+ isAuthenticated: false,
5120
+ user: void 0,
5121
+ sessionInfo: void 0,
5122
+ tokens: void 0
5123
+ }));
5124
+ }, [signOutFn]);
5125
+ (0, import_react16.useEffect)(() => {
5126
+ checkAuth();
5127
+ }, [checkAuth]);
5128
+ const contextValue = (0, import_react16.useMemo)(
5129
+ () => ({
5130
+ ...authState,
5131
+ checkAuth,
5132
+ signOut
5133
+ }),
5134
+ [authState, checkAuth, signOut]
5135
+ );
5136
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AuthContext.Provider, { value: contextValue, children });
5137
+ };
5138
+ var useAuth = () => {
5139
+ const context = (0, import_react16.useContext)(AuthContext);
5140
+ if (context === void 0) {
5141
+ throw new Error("useAuth deve ser usado dentro de um AuthProvider");
5142
+ }
5143
+ return context;
5144
+ };
5145
+ var ProtectedRoute = ({
5146
+ children,
5147
+ redirectTo = "/",
5148
+ loadingComponent,
5149
+ additionalCheck
5150
+ }) => {
5151
+ const { isAuthenticated, isLoading, ...authState } = useAuth();
5152
+ const defaultLoadingComponent = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-text-950 text-lg", children: "Carregando..." }) });
5153
+ if (isLoading) {
5154
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: loadingComponent || defaultLoadingComponent });
5155
+ }
5156
+ if (!isAuthenticated) {
5157
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom.Navigate, { to: redirectTo, replace: true });
5158
+ }
5159
+ if (additionalCheck && !additionalCheck({ isAuthenticated, isLoading, ...authState })) {
5160
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom.Navigate, { to: redirectTo, replace: true });
5161
+ }
5162
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children });
5163
+ };
5164
+ var PublicRoute = ({
5165
+ children,
5166
+ redirectTo = "/painel",
5167
+ redirectIfAuthenticated = false,
5168
+ checkAuthBeforeRender = false
5169
+ }) => {
5170
+ const { isAuthenticated, isLoading } = useAuth();
5171
+ if (checkAuthBeforeRender && isLoading) {
5172
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-text-950 text-lg", children: "Carregando..." }) });
5173
+ }
5174
+ if (isAuthenticated && redirectIfAuthenticated) {
5175
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom.Navigate, { to: redirectTo, replace: true });
5176
+ }
5177
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children });
5178
+ };
5179
+ var withAuth = (Component, options = {}) => {
5180
+ return (props) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ProtectedRoute, { ...options, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Component, { ...props }) });
5181
+ };
5182
+ var useAuthGuard = (options = {}) => {
5183
+ const authState = useAuth();
5184
+ const { requireAuth = true, customCheck } = options;
5185
+ const canAccess = !authState.isLoading && (requireAuth ? authState.isAuthenticated && (!customCheck || customCheck(authState)) : !authState.isAuthenticated || !customCheck || customCheck(authState));
5186
+ return {
5187
+ canAccess,
5188
+ isLoading: authState.isLoading,
5189
+ authState
5190
+ };
5191
+ };
5192
+ var useRouteAuth = (fallbackPath = "/") => {
5193
+ const { isAuthenticated, isLoading } = useAuth();
5194
+ const location = (0, import_react_router_dom.useLocation)();
5195
+ const redirectToLogin = () => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom.Navigate, { to: fallbackPath, state: { from: location }, replace: true });
5196
+ return {
5197
+ isAuthenticated,
5198
+ isLoading,
5199
+ redirectToLogin
5200
+ };
5201
+ };
5202
+
5203
+ // src/components/Tab/Tab.tsx
5204
+ var import_react17 = require("react");
5205
+ var import_jsx_runtime29 = require("react/jsx-runtime");
5206
+ var TAB_SIZE_CLASSES = {
5207
+ small: {
5208
+ container: "h-10 gap-1",
5209
+ tab: "px-3 py-2 text-sm",
5210
+ indicator: "h-0.5"
5211
+ },
5212
+ medium: {
5213
+ container: "h-12 gap-2",
5214
+ tab: "px-4 py-4 text-sm",
5215
+ indicator: "h-1"
5216
+ },
5217
+ large: {
5218
+ container: "h-14 gap-2",
5219
+ tab: "px-6 py-4 text-base",
5220
+ indicator: "h-1"
5221
+ }
5222
+ };
5223
+ var RESPONSIVE_WIDTH_CLASSES = {
5224
+ twoTabs: "w-[115px] sm:w-[204px]",
5225
+ threeTabs: "w-[100px] sm:w-[160px]",
5226
+ fourTabs: "w-[80px] sm:w-[140px]",
5227
+ fiveTabs: "w-[70px] sm:w-[120px]",
5228
+ default: "flex-1"
5229
+ };
5230
+ var Tab = (0, import_react17.forwardRef)(
5231
+ ({
5232
+ tabs,
5233
+ activeTab,
5234
+ onTabChange,
5235
+ size = "medium",
5236
+ responsive = true,
5237
+ className = "",
5238
+ ...props
5239
+ }, ref) => {
5240
+ const sizeClasses = TAB_SIZE_CLASSES[size];
5241
+ const getResponsiveWidthClass = (tabCount) => {
5242
+ if (!responsive) return RESPONSIVE_WIDTH_CLASSES.default;
5243
+ switch (tabCount) {
5244
+ case 2:
5245
+ return RESPONSIVE_WIDTH_CLASSES.twoTabs;
5246
+ case 3:
5247
+ return RESPONSIVE_WIDTH_CLASSES.threeTabs;
5248
+ case 4:
5249
+ return RESPONSIVE_WIDTH_CLASSES.fourTabs;
5250
+ case 5:
5251
+ return RESPONSIVE_WIDTH_CLASSES.fiveTabs;
5252
+ default:
5253
+ return RESPONSIVE_WIDTH_CLASSES.default;
5254
+ }
5255
+ };
5256
+ const handleTabClick = (tabId) => {
5257
+ const tab = tabs.find((t) => t.id === tabId);
5258
+ if (tab && !tab.disabled) {
5259
+ onTabChange(tabId);
5260
+ }
5261
+ };
5262
+ const wrapAroundIndex = (index, maxLength) => {
5263
+ if (index < 0) return maxLength - 1;
5264
+ if (index >= maxLength) return 0;
5265
+ return index;
5266
+ };
5267
+ const findNextValidTab = (startIndex, direction) => {
5268
+ let nextIndex = wrapAroundIndex(startIndex + direction, tabs.length);
5269
+ let attempts = 0;
5270
+ while (tabs[nextIndex]?.disabled && attempts < tabs.length) {
5271
+ nextIndex = wrapAroundIndex(nextIndex + direction, tabs.length);
5272
+ attempts++;
5273
+ }
5274
+ return nextIndex;
5275
+ };
5276
+ const handleArrowNavigation = (direction) => {
5277
+ const currentIndex = tabs.findIndex((tab) => tab.id === activeTab);
5278
+ const nextIndex = findNextValidTab(currentIndex, direction);
5279
+ if (!tabs[nextIndex]?.disabled && nextIndex !== currentIndex) {
5280
+ handleTabClick(tabs[nextIndex].id);
5281
+ }
5282
+ };
5283
+ const handleKeyDown = (event, tabId) => {
5284
+ if (event.key === "Enter" || event.key === " ") {
5285
+ event.preventDefault();
5286
+ handleTabClick(tabId);
5287
+ return;
5288
+ }
5289
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
5290
+ event.preventDefault();
5291
+ const direction = event.key === "ArrowLeft" ? -1 : 1;
5292
+ handleArrowNavigation(direction);
5293
+ }
5294
+ };
5295
+ const getTabClassNames = (isDisabled, isActive) => {
5296
+ if (isDisabled) {
5297
+ return "text-text-400 cursor-not-allowed opacity-50";
5298
+ }
5299
+ if (isActive) {
5300
+ return "text-text-950";
5301
+ }
5302
+ return "text-text-700 hover:text-text-800";
5303
+ };
5304
+ const tabWidthClass = getResponsiveWidthClass(tabs.length);
5305
+ const containerWidth = responsive && tabs.length <= 2 ? "w-[240px] sm:w-[416px]" : "w-full";
5306
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5307
+ "div",
5308
+ {
5309
+ ref,
5310
+ className: `flex flex-row items-start ${sizeClasses.container} ${containerWidth} ${className}`,
5311
+ role: "tablist",
5312
+ ...props,
5313
+ children: tabs.map((tab) => {
5314
+ const isActive = tab.id === activeTab;
5315
+ const isDisabled = Boolean(tab.disabled);
5316
+ const tabClassNames = getTabClassNames(isDisabled, isActive);
5317
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
5318
+ "button",
5319
+ {
5320
+ type: "button",
5321
+ role: "tab",
5322
+ "aria-selected": isActive,
5323
+ "aria-disabled": isDisabled,
5324
+ tabIndex: isActive ? 0 : -1,
5325
+ className: `
5326
+ relative flex flex-row justify-center items-center gap-2 rounded transition-colors isolate
5327
+ ${sizeClasses.tab}
5328
+ ${tabWidthClass}
5329
+ ${tabClassNames}
5330
+ ${!isDisabled && !isActive ? "hover:bg-background-50" : ""}
5331
+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2
5332
+ `,
5333
+ onClick: () => handleTabClick(tab.id),
5334
+ onKeyDown: (e) => handleKeyDown(e, tab.id),
5335
+ disabled: isDisabled,
5336
+ "data-testid": `tab-${tab.id}`,
5337
+ children: [
5338
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "font-bold leading-4 tracking-[0.2px] truncate", children: responsive && tab.mobileLabel ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
5339
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "sm:hidden", children: tab.mobileLabel }),
5340
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "hidden sm:inline", children: tab.label })
5341
+ ] }) : tab.label }),
5342
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5343
+ "div",
5344
+ {
5345
+ className: `absolute bottom-0 left-2 right-2 bg-primary-700 rounded-lg z-[2] ${sizeClasses.indicator}`,
5346
+ "data-testid": "active-indicator"
5347
+ }
5348
+ )
5349
+ ]
5350
+ },
5351
+ tab.id
5352
+ );
5353
+ })
5354
+ }
5355
+ );
5356
+ }
5357
+ );
5358
+ Tab.displayName = "Tab";
5359
+ var Tab_default = Tab;
5054
5360
  // Annotate the CommonJS export names for ESM import in node:
5055
5361
  0 && (module.exports = {
5056
5362
  Alert,
5363
+ AuthProvider,
5057
5364
  Badge,
5058
5365
  Button,
5059
5366
  Calendar,
@@ -5089,6 +5396,8 @@ var SkeletonTable = (0, import_react15.forwardRef)(
5089
5396
  ProfileMenuTrigger,
5090
5397
  ProgressBar,
5091
5398
  ProgressCircle,
5399
+ ProtectedRoute,
5400
+ PublicRoute,
5092
5401
  Radio,
5093
5402
  Select,
5094
5403
  SelectContent,
@@ -5105,11 +5414,16 @@ var SkeletonTable = (0, import_react15.forwardRef)(
5105
5414
  SkeletonTable,
5106
5415
  SkeletonText,
5107
5416
  Stepper,
5417
+ Tab,
5108
5418
  Table,
5109
5419
  Text,
5110
5420
  TextArea,
5111
5421
  Toast,
5112
5422
  Toaster,
5113
- useToastStore
5423
+ useAuth,
5424
+ useAuthGuard,
5425
+ useRouteAuth,
5426
+ useToastStore,
5427
+ withAuth
5114
5428
  });
5115
5429
  //# sourceMappingURL=index.js.map