@djangocfg/layouts 2.1.488 → 2.1.490
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/README.md +12 -0
- package/package.json +15 -15
- package/src/layouts/AuthLayout/AuthLayout.tsx +23 -0
package/README.md
CHANGED
|
@@ -171,6 +171,18 @@ Wraps `Boundary` from `@djangocfg/ui-core` — same `variant`/`fallback`/`resetK
|
|
|
171
171
|
|
|
172
172
|
For local UI widgets that should not report to backend, use `Boundary` from `@djangocfg/ui-core` directly.
|
|
173
173
|
|
|
174
|
+
## Analytics and auth funnels
|
|
175
|
+
|
|
176
|
+
`BaseApp` mounts the first-party `AnalyticsProvider` once and bridges events
|
|
177
|
+
from `@djangocfg/api/auth`. `AuthLayout` adds a small `layouts.auth.step_viewed`
|
|
178
|
+
breadcrumb at each visible step; the server-confirmed `auth_login_success`
|
|
179
|
+
event remains the conversion source of truth.
|
|
180
|
+
|
|
181
|
+
For a custom product goal, use `useAnalytics().event(name, props)` from
|
|
182
|
+
`@djangocfg/analytics`. See that package's README for the typed event catalog,
|
|
183
|
+
browser facade, and extension pattern. Do not create a second route listener or
|
|
184
|
+
send analytics directly from a layout.
|
|
185
|
+
|
|
174
186
|
---
|
|
175
187
|
|
|
176
188
|
## Package exports
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.490",
|
|
4
4
|
"description": "Simple, straightforward layout components for Next.js - import and use with props",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -89,12 +89,12 @@
|
|
|
89
89
|
"check": "tsc --noEmit"
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
|
92
|
-
"@djangocfg/analytics": "^2.1.
|
|
93
|
-
"@djangocfg/api": "^2.1.
|
|
94
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
95
|
-
"@djangocfg/devtools": "^2.1.
|
|
96
|
-
"@djangocfg/i18n": "^2.1.
|
|
97
|
-
"@djangocfg/ui-core": "^2.1.
|
|
92
|
+
"@djangocfg/analytics": "^2.1.490",
|
|
93
|
+
"@djangocfg/api": "^2.1.490",
|
|
94
|
+
"@djangocfg/centrifugo": "^2.1.490",
|
|
95
|
+
"@djangocfg/devtools": "^2.1.490",
|
|
96
|
+
"@djangocfg/i18n": "^2.1.490",
|
|
97
|
+
"@djangocfg/ui-core": "^2.1.490",
|
|
98
98
|
"@hookform/resolvers": "^5.2.2",
|
|
99
99
|
"consola": "^3.4.2",
|
|
100
100
|
"lucide-react": "^0.545.0",
|
|
@@ -124,14 +124,14 @@
|
|
|
124
124
|
"uuid": "^11.1.1"
|
|
125
125
|
},
|
|
126
126
|
"devDependencies": {
|
|
127
|
-
"@djangocfg/analytics": "^2.1.
|
|
128
|
-
"@djangocfg/api": "^2.1.
|
|
129
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
130
|
-
"@djangocfg/devtools": "^2.1.
|
|
131
|
-
"@djangocfg/i18n": "^2.1.
|
|
132
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
133
|
-
"@djangocfg/ui-core": "^2.1.
|
|
134
|
-
"@djangocfg/ui-tools": "^2.1.
|
|
127
|
+
"@djangocfg/analytics": "^2.1.490",
|
|
128
|
+
"@djangocfg/api": "^2.1.490",
|
|
129
|
+
"@djangocfg/centrifugo": "^2.1.490",
|
|
130
|
+
"@djangocfg/devtools": "^2.1.490",
|
|
131
|
+
"@djangocfg/i18n": "^2.1.490",
|
|
132
|
+
"@djangocfg/typescript-config": "^2.1.490",
|
|
133
|
+
"@djangocfg/ui-core": "^2.1.490",
|
|
134
|
+
"@djangocfg/ui-tools": "^2.1.490",
|
|
135
135
|
"@types/node": "^25.9.5",
|
|
136
136
|
"@types/react": "19.2.15",
|
|
137
137
|
"@types/react-dom": "19.2.3",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import React, { createContext, memo, useContext, useMemo } from 'react';
|
|
14
14
|
|
|
15
15
|
import { consumeSavedRedirect, useAuth, useCfgRouter } from '@djangocfg/api/auth';
|
|
16
|
+
import { useAnalytics } from '@djangocfg/analytics';
|
|
16
17
|
import { useAppT } from '@djangocfg/i18n';
|
|
17
18
|
|
|
18
19
|
import { Suspense } from '../../components';
|
|
@@ -81,6 +82,7 @@ export const AuthLayout: React.FC<AuthLayoutProps> = (props) => {
|
|
|
81
82
|
<AuthLayoutContext.Provider value={layoutContextValue}>
|
|
82
83
|
{/* Full-screen success overlay */}
|
|
83
84
|
<AuthSuccessOverlay />
|
|
85
|
+
<AuthFunnelTracker />
|
|
84
86
|
|
|
85
87
|
<AuthShell variant={variant} mediaSide={mediaSide} background={background} sidebar={sidebar} className={className}>
|
|
86
88
|
{/* Handle OAuth callback when GitHub auth is enabled */}
|
|
@@ -95,6 +97,27 @@ export const AuthLayout: React.FC<AuthLayoutProps> = (props) => {
|
|
|
95
97
|
);
|
|
96
98
|
};
|
|
97
99
|
|
|
100
|
+
/**
|
|
101
|
+
* A lightweight UI breadcrumb around the server-confirmed auth events.
|
|
102
|
+
*
|
|
103
|
+
* `auth_login_success` remains server-authoritative. This event only answers
|
|
104
|
+
* where a person stopped in the layout, and quietly becomes a no-op when an
|
|
105
|
+
* app intentionally does not mount AnalyticsProvider.
|
|
106
|
+
*/
|
|
107
|
+
const AuthFunnelTracker: React.FC = memo(() => {
|
|
108
|
+
const { step } = useAuthFormContext();
|
|
109
|
+
const { event, isEnabled } = useAnalytics();
|
|
110
|
+
const lastStep = React.useRef<string | null>(null);
|
|
111
|
+
|
|
112
|
+
React.useEffect(() => {
|
|
113
|
+
if (!isEnabled || lastStep.current === step) return;
|
|
114
|
+
lastStep.current = step;
|
|
115
|
+
event('layouts.auth.step_viewed', { step });
|
|
116
|
+
}, [event, isEnabled, step]);
|
|
117
|
+
|
|
118
|
+
return null;
|
|
119
|
+
});
|
|
120
|
+
|
|
98
121
|
/** Renders custom children only on the identifier step — hides them on otp / 2fa / etc. */
|
|
99
122
|
const AuthHeaderSlot: React.FC<{ children?: React.ReactNode }> = memo(({ children }) => {
|
|
100
123
|
const { step } = useAuthFormContext();
|