mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 22:18:12 +00:00
feat: setup posthog
This commit is contained in:
@@ -4,3 +4,8 @@ VITE_BASE_API_URL=http://localhost:3001
|
|||||||
# Proactive token refresh cadence (minutes). Must stay well under the 60-min
|
# Proactive token refresh cadence (minutes). Must stay well under the 60-min
|
||||||
# server session window. Default: 10.
|
# server session window. Default: 10.
|
||||||
VITE_TOKEN_REFRESH_INTERVAL_MINUTES=10
|
VITE_TOKEN_REFRESH_INTERVAL_MINUTES=10
|
||||||
|
|
||||||
|
# PostHog — session replay, error tracking, console logs. Both must be set or
|
||||||
|
# observability stays off (the app works either way). Self-hosted instance.
|
||||||
|
VITE_POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
VITE_POSTHOG_HOST=https://posthog.example.com
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@mantine/core": "^9.3.0",
|
"@mantine/core": "^9.3.0",
|
||||||
"@mantine/dates": "^9.3.0",
|
"@mantine/dates": "^9.3.0",
|
||||||
"@mantine/hooks": "^9.3.0",
|
"@mantine/hooks": "^9.3.0",
|
||||||
|
"@posthog/react": "^1.10.3",
|
||||||
"@radix-ui/react-accordion": "^1.2.13",
|
"@radix-ui/react-accordion": "^1.2.13",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.16",
|
"@radix-ui/react-alert-dialog": "^1.1.16",
|
||||||
"@radix-ui/react-avatar": "^1.1.12",
|
"@radix-ui/react-avatar": "^1.1.12",
|
||||||
@@ -76,6 +77,7 @@
|
|||||||
"lucide-react": "^1.14.0",
|
"lucide-react": "^1.14.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
|
"posthog-js": "^1.400.1",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"qs": "^6.15.2",
|
"qs": "^6.15.2",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
type ReactNode,
|
type ReactNode,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
|
import { useIdentify } from "@/lib/posthog";
|
||||||
import { getMeRequest, loginRequest, verifyMfaRequest } from "./api";
|
import { getMeRequest, loginRequest, verifyMfaRequest } from "./api";
|
||||||
import {
|
import {
|
||||||
AUTH_TOKEN_COOKIE,
|
AUTH_TOKEN_COOKIE,
|
||||||
@@ -69,6 +70,9 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const mfaEmailRef = useRef<string | null>(null);
|
const mfaEmailRef = useRef<string | null>(null);
|
||||||
|
|
||||||
|
// Attribute replays and exceptions to the signed-in user (id/org only).
|
||||||
|
useIdentify(user);
|
||||||
|
|
||||||
const loadCurrentUser = async () => {
|
const loadCurrentUser = async () => {
|
||||||
const currentUser = await getMeRequest();
|
const currentUser = await getMeRequest();
|
||||||
setUser(currentUser);
|
setUser(currentUser);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
emitApiError,
|
emitApiError,
|
||||||
extractApiErrorPayload,
|
extractApiErrorPayload,
|
||||||
} from "@/components/errors/ApiErrorModal";
|
} from "@/components/errors/ApiErrorModal";
|
||||||
|
import { captureApiError } from "@/lib/posthog";
|
||||||
import {
|
import {
|
||||||
AUTH_TOKEN_COOKIE,
|
AUTH_TOKEN_COOKIE,
|
||||||
REFRESH_TOKEN_COOKIE,
|
REFRESH_TOKEN_COOKIE,
|
||||||
@@ -82,6 +83,14 @@ api.interceptors.response.use(
|
|||||||
async (error) => {
|
async (error) => {
|
||||||
const originalRequest = error.config as RetriableRequest | undefined;
|
const originalRequest = error.config as RetriableRequest | undefined;
|
||||||
|
|
||||||
|
// Report the failure to PostHog. Hooked here rather than inside
|
||||||
|
// `emitApiError`, which stays silent on suppressed paths (warehouse /
|
||||||
|
// mile / onboarding) — those failures still need reporting.
|
||||||
|
// 401s are skipped: an expired session is refreshed below, not a defect.
|
||||||
|
if (!error.response || error.response.status !== 401) {
|
||||||
|
captureApiError(error);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
error.response?.status !== 401 ||
|
error.response?.status !== 401 ||
|
||||||
!originalRequest ||
|
!originalRequest ||
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { Component, type ErrorInfo, type ReactNode } from "react";
|
import { Component, type ErrorInfo, type ReactNode } from "react";
|
||||||
|
|
||||||
|
import { captureException } from "@/lib/posthog";
|
||||||
|
|
||||||
interface ErrorBoundaryProps {
|
interface ErrorBoundaryProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
@@ -21,6 +23,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidCatch(error: Error, info: ErrorInfo) {
|
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||||
|
captureException(error, { componentStack: info.componentStack });
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error("[ErrorBoundary] Uncaught render error:", error, info.componentStack);
|
console.error("[ErrorBoundary] Uncaught render error:", error, info.componentStack);
|
||||||
}
|
}
|
||||||
|
|||||||
140
apps/edr-freight-web/backoffice/src/lib/posthog.ts
Normal file
140
apps/edr-freight-web/backoffice/src/lib/posthog.ts
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/**
|
||||||
|
* PostHog wiring — session replay, exception capture, console logs.
|
||||||
|
*
|
||||||
|
* NOTE: `portal/src/lib/posthog.ts` is the twin of this file. The init config
|
||||||
|
* below (masking rules) and the PII allowlist in `useIdentify` MUST be kept
|
||||||
|
* identical in both — a change made here alone silently leaks staff data into
|
||||||
|
* the other app's replays.
|
||||||
|
*
|
||||||
|
* This is instrumentation, not analytics: autocapture is off and no product
|
||||||
|
* events are sent.
|
||||||
|
*/
|
||||||
|
import posthog from "posthog-js";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
import type { AuthUser } from "@/auth/types";
|
||||||
|
|
||||||
|
const APP = "freight-backoffice";
|
||||||
|
|
||||||
|
const TOKEN = import.meta.env.VITE_POSTHOG_KEY;
|
||||||
|
const HOST = import.meta.env.VITE_POSTHOG_HOST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether init actually ran. Without a token every export below is a no-op, so
|
||||||
|
* local dev and any environment whose env file lacks the vars keeps working —
|
||||||
|
* a missing observability token must never break the app.
|
||||||
|
*/
|
||||||
|
let enabled = false;
|
||||||
|
|
||||||
|
export function initPostHog(): void {
|
||||||
|
if (enabled || !TOKEN || !HOST) return;
|
||||||
|
|
||||||
|
posthog.init(TOKEN, {
|
||||||
|
api_host: HOST,
|
||||||
|
defaults: "2026-05-30",
|
||||||
|
|
||||||
|
// Debuggability, not analytics.
|
||||||
|
autocapture: false,
|
||||||
|
capture_pageview: true,
|
||||||
|
capture_pageleave: true,
|
||||||
|
disable_surveys: true,
|
||||||
|
person_profiles: "identified_only",
|
||||||
|
|
||||||
|
capture_exceptions: {
|
||||||
|
capture_unhandled_errors: true,
|
||||||
|
capture_unhandled_rejections: true,
|
||||||
|
capture_console_errors: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Off by default; this is half the point of the integration.
|
||||||
|
enable_recording_console_log: true,
|
||||||
|
|
||||||
|
// Inputs are masked; rendered text stays visible so replays are readable.
|
||||||
|
// Wrap sensitive elements in `ph-no-capture` to blank them individually.
|
||||||
|
session_recording: { maskAllInputs: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Portal and backoffice share one PostHog project — filter by this.
|
||||||
|
posthog.register({ app: APP });
|
||||||
|
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function captureException(
|
||||||
|
error: unknown,
|
||||||
|
properties?: Record<string, unknown>,
|
||||||
|
): void {
|
||||||
|
if (!enabled) return;
|
||||||
|
posthog.captureException(error, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report a failed API call.
|
||||||
|
*
|
||||||
|
* Called from the axios interceptor rather than from `emitApiError`, which
|
||||||
|
* early-returns on suppressed paths (warehouse / first-mile / onboarding /
|
||||||
|
* auth) — hooking there would drop errors on exactly those pages.
|
||||||
|
*
|
||||||
|
* 5xx and network failures are real defects and go to Error tracking. 4xx is
|
||||||
|
* usually the server correctly rejecting input, so it is recorded as a plain
|
||||||
|
* event to keep the issue list signal-heavy.
|
||||||
|
*/
|
||||||
|
export function captureApiError(error: unknown): void {
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
const err = error as {
|
||||||
|
message?: string;
|
||||||
|
config?: { method?: string; url?: string };
|
||||||
|
response?: { status?: number };
|
||||||
|
};
|
||||||
|
|
||||||
|
const status = err.response?.status;
|
||||||
|
const properties = {
|
||||||
|
api_status: status ?? null,
|
||||||
|
api_method: err.config?.method?.toUpperCase() ?? null,
|
||||||
|
api_path: err.config?.url ?? null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (status && status < 500) {
|
||||||
|
posthog.capture("api_error", properties);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
posthog.captureException(error, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify the current user to PostHog so replays and exceptions are
|
||||||
|
* attributable.
|
||||||
|
*
|
||||||
|
* Deliberately sends NO contact details. `AuthUser` carries email, phoneNumber,
|
||||||
|
* name and username; these are railway staff, and debugging a replay never
|
||||||
|
* requires knowing how to phone the person in it.
|
||||||
|
*/
|
||||||
|
export function useIdentify(user: AuthUser | null): void {
|
||||||
|
const employee = user?.employee?.[0];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
if (!user?.id) {
|
||||||
|
posthog.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
posthog.identify(user.id, {
|
||||||
|
roles: user.roles?.map((role) => role.key ?? role.id),
|
||||||
|
status: user.status,
|
||||||
|
is_super_admin: user.isSuperAdmin,
|
||||||
|
organization_id: employee?.organizationId,
|
||||||
|
unit_id: employee?.unitId,
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
user?.id,
|
||||||
|
user?.roles,
|
||||||
|
user?.status,
|
||||||
|
user?.isSuperAdmin,
|
||||||
|
employee?.organizationId,
|
||||||
|
employee?.unitId,
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ import { StrictMode } from "react";
|
|||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import { MantineProvider } from "@mantine/core";
|
import { MantineProvider } from "@mantine/core";
|
||||||
|
import posthog from "posthog-js";
|
||||||
|
import { PostHogProvider } from "@posthog/react";
|
||||||
import "@mantine/core/styles.css";
|
import "@mantine/core/styles.css";
|
||||||
import "@mantine/dates/styles.css";
|
import "@mantine/dates/styles.css";
|
||||||
import "@edr/ui-common/styles.css";
|
import "@edr/ui-common/styles.css";
|
||||||
@@ -19,6 +21,7 @@ import { ApiErrorModal } from "./components/errors/ApiErrorModal";
|
|||||||
import { ErrorBoundary } from "./components/ErrorBoundary";
|
import { ErrorBoundary } from "./components/ErrorBoundary";
|
||||||
import { AuthProvider } from "./auth/AuthProvider";
|
import { AuthProvider } from "./auth/AuthProvider";
|
||||||
import { queryClient } from "./lib/queryClient";
|
import { queryClient } from "./lib/queryClient";
|
||||||
|
import { initPostHog } from "./lib/posthog";
|
||||||
import { freightMantineTheme } from "./theme/freight-brand";
|
import { freightMantineTheme } from "./theme/freight-brand";
|
||||||
import { QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
|
||||||
@@ -43,6 +46,10 @@ const applyStoredTheme = () => {
|
|||||||
|
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
|
|
||||||
|
// Must run before render so replay and exception capture cover startup errors.
|
||||||
|
// No-ops when VITE_POSTHOG_KEY is unset.
|
||||||
|
initPostHog();
|
||||||
|
|
||||||
const rootElement = document.getElementById("root");
|
const rootElement = document.getElementById("root");
|
||||||
|
|
||||||
if (!rootElement) {
|
if (!rootElement) {
|
||||||
@@ -50,23 +57,25 @@ if (!rootElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createRoot(rootElement).render(
|
createRoot(rootElement).render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<PostHogProvider client={posthog}>
|
||||||
<MantineProvider theme={freightMantineTheme}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<StrictMode>
|
<MantineProvider theme={freightMantineTheme}>
|
||||||
<BrowserRouter>
|
<StrictMode>
|
||||||
<AuthProvider>
|
<BrowserRouter>
|
||||||
<ErrorBoundary>
|
<AuthProvider>
|
||||||
<App />
|
<ErrorBoundary>
|
||||||
</ErrorBoundary>
|
<App />
|
||||||
{/* Global API error modal — shows the server's actual error
|
</ErrorBoundary>
|
||||||
message (suppressed on warehouse / mile / onboarding pages). */}
|
{/* Global API error modal — shows the server's actual error
|
||||||
<ApiErrorModal />
|
message (suppressed on warehouse / mile / onboarding pages). */}
|
||||||
<Toaster position="top-right" />
|
<ApiErrorModal />
|
||||||
</AuthProvider>
|
<Toaster position="top-right" />
|
||||||
</BrowserRouter>
|
</AuthProvider>
|
||||||
</StrictMode>
|
</BrowserRouter>
|
||||||
</MantineProvider>
|
</StrictMode>
|
||||||
</QueryClientProvider>
|
</MantineProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</PostHogProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
// run
|
// run
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import React, { Component, ErrorInfo, ReactNode } from "react";
|
import React, { Component, ErrorInfo, ReactNode } from "react";
|
||||||
|
|
||||||
|
import { captureException } from "@/lib/posthog";
|
||||||
|
|
||||||
interface ErrorBoundaryProps {
|
interface ErrorBoundaryProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
@@ -20,7 +22,8 @@ export class ErrorBoundary extends Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidCatch(error: Error, info: ErrorInfo) {
|
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||||
// Log to console in development; replace with a reporting service (e.g. Sentry) in production
|
captureException(error, { componentStack: info.componentStack });
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
console.error("ErrorBoundary caught:", error, info.componentStack);
|
console.error("ErrorBoundary caught:", error, info.componentStack);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ interface Window {
|
|||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_API_URL: string;
|
readonly VITE_API_URL: string;
|
||||||
readonly VITE_BASE_API_URL: string;
|
readonly VITE_BASE_API_URL: string;
|
||||||
|
readonly VITE_TOKEN_REFRESH_INTERVAL_MINUTES?: string;
|
||||||
|
/** PostHog project token. Absent = observability disabled (see lib/posthog.ts). */
|
||||||
|
readonly VITE_POSTHOG_KEY?: string;
|
||||||
|
/** Self-hosted PostHog instance URL. */
|
||||||
|
readonly VITE_POSTHOG_HOST?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"@mantine/core": "^9.3.0",
|
"@mantine/core": "^9.3.0",
|
||||||
"@mantine/dates": "^9.3.0",
|
"@mantine/dates": "^9.3.0",
|
||||||
"@mantine/hooks": "^9.3.0",
|
"@mantine/hooks": "^9.3.0",
|
||||||
|
"@posthog/react": "^1.10.3",
|
||||||
"@tanstack/react-query": "^5.59.0",
|
"@tanstack/react-query": "^5.59.0",
|
||||||
"@tria-plc/iamui": "file:../../../local-packages/tria-plc-iamui-0.1.1.tgz",
|
"@tria-plc/iamui": "file:../../../local-packages/tria-plc-iamui-0.1.1.tgz",
|
||||||
"@vis.gl/react-google-maps": "^1.8.3",
|
"@vis.gl/react-google-maps": "^1.8.3",
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"lucide-react": "^1.14.0",
|
"lucide-react": "^1.14.0",
|
||||||
|
"posthog-js": "^1.400.1",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
"react": "19.2.6",
|
"react": "19.2.6",
|
||||||
"react-dom": "19.2.6",
|
"react-dom": "19.2.6",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import OnboardingResumeBanner, {
|
|||||||
import OnboardingWizardDialog from "./components/onboarding/OnboardingWizardDialog";
|
import OnboardingWizardDialog from "./components/onboarding/OnboardingWizardDialog";
|
||||||
import { ApiErrorModal } from "./components/errors/ApiErrorModal";
|
import { ApiErrorModal } from "./components/errors/ApiErrorModal";
|
||||||
import useAuth from "./hooks/useAuth";
|
import useAuth from "./hooks/useAuth";
|
||||||
|
import { useIdentify } from "./lib/posthog";
|
||||||
import {
|
import {
|
||||||
startTokenRefreshScheduler,
|
startTokenRefreshScheduler,
|
||||||
stopTokenRefreshScheduler,
|
stopTokenRefreshScheduler,
|
||||||
@@ -221,6 +222,9 @@ const App = () => {
|
|||||||
const { user, company, companyType, createProfile, isAuthenticated } =
|
const { user, company, companyType, createProfile, isAuthenticated } =
|
||||||
useAuth();
|
useAuth();
|
||||||
|
|
||||||
|
// Attribute replays and exceptions to the signed-in user (id/org only).
|
||||||
|
useIdentify(user, company);
|
||||||
|
|
||||||
// Keep the server session alive while a user is logged in. Runs after
|
// Keep the server session alive while a user is logged in. Runs after
|
||||||
// login, signup, and page-reload bootstrap alike.
|
// login, signup, and page-reload bootstrap alike.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Shown when a render error escapes to the app root.
|
||||||
|
*
|
||||||
|
* Before this existed, a render exception unmounted the tree and left the
|
||||||
|
* customer staring at a blank white page with no way forward. The matching
|
||||||
|
* `$exception` is reported by the surrounding PostHogErrorBoundary.
|
||||||
|
*/
|
||||||
|
export function AppErrorFallback() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen items-center justify-center bg-slate-50 p-6">
|
||||||
|
<div className="w-full max-w-md rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-900">
|
||||||
|
Something went wrong
|
||||||
|
</h2>
|
||||||
|
<p className="mt-2 text-sm text-slate-600">
|
||||||
|
This page failed to load. The problem has been reported. Try reloading
|
||||||
|
— if it keeps happening, please contact support.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => window.location.reload()}
|
||||||
|
className="mt-4 rounded-lg bg-teal-700 px-4 py-2 text-sm font-medium text-white hover:bg-teal-800"
|
||||||
|
>
|
||||||
|
Reload page
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppErrorFallback;
|
||||||
151
apps/edr-freight-web/portal/src/lib/posthog.ts
Normal file
151
apps/edr-freight-web/portal/src/lib/posthog.ts
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/**
|
||||||
|
* PostHog wiring — session replay, exception capture, console logs.
|
||||||
|
*
|
||||||
|
* NOTE: `backoffice/src/lib/posthog.ts` is the twin of this file. The init
|
||||||
|
* config below (masking rules) and the PII allowlist in `useIdentify` MUST be
|
||||||
|
* kept identical in both — a change made here alone silently leaks customer
|
||||||
|
* data into the other app's replays.
|
||||||
|
*
|
||||||
|
* This is instrumentation, not analytics: autocapture is off and no product
|
||||||
|
* events are sent.
|
||||||
|
*/
|
||||||
|
import posthog from "posthog-js";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
import type { AuthUser } from "@/types/auth";
|
||||||
|
|
||||||
|
const APP = "freight-portal";
|
||||||
|
|
||||||
|
const TOKEN = import.meta.env.VITE_POSTHOG_KEY;
|
||||||
|
const HOST = import.meta.env.VITE_POSTHOG_HOST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether init actually ran. Without a token every export below is a no-op, so
|
||||||
|
* local dev and any environment whose env file lacks the vars keeps working —
|
||||||
|
* a missing observability token must never break the app.
|
||||||
|
*/
|
||||||
|
let enabled = false;
|
||||||
|
|
||||||
|
export function initPostHog(): void {
|
||||||
|
if (enabled || !TOKEN || !HOST) return;
|
||||||
|
|
||||||
|
posthog.init(TOKEN, {
|
||||||
|
api_host: HOST,
|
||||||
|
defaults: "2026-05-30",
|
||||||
|
|
||||||
|
// Debuggability, not analytics.
|
||||||
|
autocapture: false,
|
||||||
|
capture_pageview: true,
|
||||||
|
capture_pageleave: true,
|
||||||
|
disable_surveys: true,
|
||||||
|
person_profiles: "identified_only",
|
||||||
|
|
||||||
|
capture_exceptions: {
|
||||||
|
capture_unhandled_errors: true,
|
||||||
|
capture_unhandled_rejections: true,
|
||||||
|
capture_console_errors: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Off by default; this is half the point of the integration.
|
||||||
|
enable_recording_console_log: true,
|
||||||
|
|
||||||
|
// Inputs are masked; rendered text stays visible so replays are readable.
|
||||||
|
// Wrap sensitive elements in `ph-no-capture` to blank them individually.
|
||||||
|
session_recording: { maskAllInputs: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Portal and backoffice share one PostHog project — filter by this.
|
||||||
|
posthog.register({ app: APP });
|
||||||
|
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function captureException(
|
||||||
|
error: unknown,
|
||||||
|
properties?: Record<string, unknown>,
|
||||||
|
): void {
|
||||||
|
if (!enabled) return;
|
||||||
|
posthog.captureException(error, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report a failed API call.
|
||||||
|
*
|
||||||
|
* Called from the axios interceptor rather than from `emitApiError`, which
|
||||||
|
* early-returns on suppressed paths (warehouse / first-mile / onboarding /
|
||||||
|
* auth) — hooking there would drop errors on exactly those pages.
|
||||||
|
*
|
||||||
|
* 5xx and network failures are real defects and go to Error tracking. 4xx is
|
||||||
|
* usually the server correctly rejecting input, so it is recorded as a plain
|
||||||
|
* event to keep the issue list signal-heavy.
|
||||||
|
*/
|
||||||
|
export function captureApiError(error: unknown): void {
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
const err = error as {
|
||||||
|
message?: string;
|
||||||
|
config?: { method?: string; url?: string };
|
||||||
|
response?: { status?: number };
|
||||||
|
};
|
||||||
|
|
||||||
|
const status = err.response?.status;
|
||||||
|
const properties = {
|
||||||
|
api_status: status ?? null,
|
||||||
|
api_method: err.config?.method?.toUpperCase() ?? null,
|
||||||
|
api_path: err.config?.url ?? null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (status && status < 500) {
|
||||||
|
posthog.capture("api_error", properties);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
posthog.captureException(error, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Company context, as returned by `useAuth().company`. */
|
||||||
|
interface IdentifyCompany {
|
||||||
|
company?: { id?: string; type?: string | null; status?: string | null } | null;
|
||||||
|
profile?: { activeProfileType?: string | null } | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify the current user to PostHog so replays and exceptions are
|
||||||
|
* attributable.
|
||||||
|
*
|
||||||
|
* Deliberately sends NO contact details. `AuthUser` carries email, phoneNumber,
|
||||||
|
* name and username; these are real customers, and debugging a replay never
|
||||||
|
* requires knowing how to phone the person in it.
|
||||||
|
*/
|
||||||
|
export function useIdentify(
|
||||||
|
user: AuthUser | null,
|
||||||
|
company?: IdentifyCompany | null,
|
||||||
|
): void {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
if (!user?.id) {
|
||||||
|
posthog.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
posthog.identify(user.id, {
|
||||||
|
roles: user.roles,
|
||||||
|
status: user.status,
|
||||||
|
user_type: user.userType,
|
||||||
|
company_id: company?.company?.id,
|
||||||
|
company_type: company?.company?.type,
|
||||||
|
company_status: company?.company?.status,
|
||||||
|
active_profile_type: company?.profile?.activeProfileType,
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
user?.id,
|
||||||
|
user?.roles,
|
||||||
|
user?.status,
|
||||||
|
user?.userType,
|
||||||
|
company?.company?.id,
|
||||||
|
company?.company?.type,
|
||||||
|
company?.company?.status,
|
||||||
|
company?.profile?.activeProfileType,
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ import { createRoot } from "react-dom/client";
|
|||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { MantineProvider } from "@mantine/core";
|
import { MantineProvider } from "@mantine/core";
|
||||||
|
import posthog from "posthog-js";
|
||||||
|
import { PostHogProvider, PostHogErrorBoundary } from "@posthog/react";
|
||||||
import "@mantine/core/styles.css";
|
import "@mantine/core/styles.css";
|
||||||
import "@mantine/dates/styles.css";
|
import "@mantine/dates/styles.css";
|
||||||
import "@edr/ui-common/styles.css";
|
import "@edr/ui-common/styles.css";
|
||||||
@@ -10,6 +12,8 @@ import "../index.css";
|
|||||||
import "@edr/ui-common/theme.css";
|
import "@edr/ui-common/theme.css";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import { mantineTheme } from "./theme/mantine";
|
import { mantineTheme } from "./theme/mantine";
|
||||||
|
import { initPostHog } from "./lib/posthog";
|
||||||
|
import { AppErrorFallback } from "./components/errors/AppErrorFallback";
|
||||||
|
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
@@ -26,6 +30,10 @@ import App from "./App";
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Must run before render so replay and exception capture cover startup errors.
|
||||||
|
// No-ops when VITE_POSTHOG_KEY is unset.
|
||||||
|
initPostHog();
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
const rootElement = document.getElementById("root");
|
const rootElement = document.getElementById("root");
|
||||||
@@ -36,13 +44,17 @@ if (!rootElement) {
|
|||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<MantineProvider theme={mantineTheme} defaultColorScheme="light">
|
<PostHogProvider client={posthog}>
|
||||||
<QueryClientProvider client={queryClient}>
|
<MantineProvider theme={mantineTheme} defaultColorScheme="light">
|
||||||
<BrowserRouter>
|
<QueryClientProvider client={queryClient}>
|
||||||
<App />
|
<BrowserRouter>
|
||||||
<Toaster position="top-right" />
|
<PostHogErrorBoundary fallback={<AppErrorFallback />}>
|
||||||
</BrowserRouter>
|
<App />
|
||||||
</QueryClientProvider>
|
</PostHogErrorBoundary>
|
||||||
</MantineProvider>
|
<Toaster position="top-right" />
|
||||||
|
</BrowserRouter>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</MantineProvider>
|
||||||
|
</PostHogProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
emitApiError,
|
emitApiError,
|
||||||
extractApiErrorPayload,
|
extractApiErrorPayload,
|
||||||
} from "@/components/errors/ApiErrorModal";
|
} from "@/components/errors/ApiErrorModal";
|
||||||
|
import { captureApiError } from "@/lib/posthog";
|
||||||
|
|
||||||
const client = axios.create({
|
const client = axios.create({
|
||||||
baseURL: API_BASE_URL,
|
baseURL: API_BASE_URL,
|
||||||
@@ -91,6 +92,14 @@ client.interceptors.response.use(
|
|||||||
_retry?: boolean;
|
_retry?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Report the failure to PostHog. Hooked here rather than inside
|
||||||
|
// `emitApiError`, which stays silent on suppressed paths (warehouse /
|
||||||
|
// mile / onboarding) — those failures still need reporting.
|
||||||
|
// 401s are skipped: an expired session is refreshed below, not a defect.
|
||||||
|
if (!error.response || error.response.status !== 401) {
|
||||||
|
captureApiError(error);
|
||||||
|
}
|
||||||
|
|
||||||
// Don't intercept if:
|
// Don't intercept if:
|
||||||
// - no response (network error)
|
// - no response (network error)
|
||||||
// - status is not 401
|
// - status is not 401
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ interface Window {
|
|||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_API_URL: string;
|
readonly VITE_API_URL: string;
|
||||||
|
readonly VITE_BASE_API_URL: string;
|
||||||
readonly VITE_GOOGLE_MAPS_API_KEY?: string;
|
readonly VITE_GOOGLE_MAPS_API_KEY?: string;
|
||||||
|
readonly VITE_TOKEN_REFRESH_INTERVAL_MINUTES?: string;
|
||||||
|
/** PostHog project token. Absent = observability disabled (see lib/posthog.ts). */
|
||||||
|
readonly VITE_POSTHOG_KEY?: string;
|
||||||
|
/** Self-hosted PostHog instance URL. */
|
||||||
|
readonly VITE_POSTHOG_HOST?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ services:
|
|||||||
VITE_BASE_API_URL: ${VITE_BASE_API_URL:-}
|
VITE_BASE_API_URL: ${VITE_BASE_API_URL:-}
|
||||||
VITE_USER_MANAGEMENT_BASE: ${VITE_USER_MANAGEMENT_BASE:-}
|
VITE_USER_MANAGEMENT_BASE: ${VITE_USER_MANAGEMENT_BASE:-}
|
||||||
VITE_GOOGLE_MAPS_API_KEY: ${VITE_GOOGLE_MAPS_API_KEY:-}
|
VITE_GOOGLE_MAPS_API_KEY: ${VITE_GOOGLE_MAPS_API_KEY:-}
|
||||||
|
VITE_POSTHOG_KEY: ${VITE_POSTHOG_KEY:-}
|
||||||
|
VITE_POSTHOG_HOST: ${VITE_POSTHOG_HOST:-}
|
||||||
secrets:
|
secrets:
|
||||||
- npmrc
|
- npmrc
|
||||||
ports:
|
ports:
|
||||||
@@ -72,6 +74,8 @@ services:
|
|||||||
VITE_BASE_API_URL: ${VITE_BASE_API_URL:-}
|
VITE_BASE_API_URL: ${VITE_BASE_API_URL:-}
|
||||||
VITE_USER_MANAGEMENT_BASE: ${VITE_USER_MANAGEMENT_BASE:-}
|
VITE_USER_MANAGEMENT_BASE: ${VITE_USER_MANAGEMENT_BASE:-}
|
||||||
VITE_GOOGLE_MAPS_API_KEY: ${VITE_GOOGLE_MAPS_API_KEY:-}
|
VITE_GOOGLE_MAPS_API_KEY: ${VITE_GOOGLE_MAPS_API_KEY:-}
|
||||||
|
VITE_POSTHOG_KEY: ${VITE_POSTHOG_KEY:-}
|
||||||
|
VITE_POSTHOG_HOST: ${VITE_POSTHOG_HOST:-}
|
||||||
secrets:
|
secrets:
|
||||||
- npmrc
|
- npmrc
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -28,11 +28,15 @@ ARG VITE_BASE_API_URL
|
|||||||
ARG VITE_USER_MANAGEMENT_BASE
|
ARG VITE_USER_MANAGEMENT_BASE
|
||||||
ARG NEXT_PUBLIC_API_URL
|
ARG NEXT_PUBLIC_API_URL
|
||||||
ARG VITE_GOOGLE_MAPS_API_KEY
|
ARG VITE_GOOGLE_MAPS_API_KEY
|
||||||
|
ARG VITE_POSTHOG_KEY
|
||||||
|
ARG VITE_POSTHOG_HOST
|
||||||
ENV VITE_API_URL=${VITE_API_URL}
|
ENV VITE_API_URL=${VITE_API_URL}
|
||||||
ENV VITE_BASE_API_URL=${VITE_BASE_API_URL}
|
ENV VITE_BASE_API_URL=${VITE_BASE_API_URL}
|
||||||
ENV VITE_USER_MANAGEMENT_BASE=${VITE_USER_MANAGEMENT_BASE}
|
ENV VITE_USER_MANAGEMENT_BASE=${VITE_USER_MANAGEMENT_BASE}
|
||||||
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||||
ENV VITE_GOOGLE_MAPS_API_KEY=${VITE_GOOGLE_MAPS_API_KEY}
|
ENV VITE_GOOGLE_MAPS_API_KEY=${VITE_GOOGLE_MAPS_API_KEY}
|
||||||
|
ENV VITE_POSTHOG_KEY=${VITE_POSTHOG_KEY}
|
||||||
|
ENV VITE_POSTHOG_HOST=${VITE_POSTHOG_HOST}
|
||||||
|
|
||||||
RUN if [ -z "$VITE_API_URL" ] || [ -z "$VITE_BASE_API_URL" ] || [ -z "$VITE_USER_MANAGEMENT_BASE" ]; then \
|
RUN if [ -z "$VITE_API_URL" ] || [ -z "$VITE_BASE_API_URL" ] || [ -z "$VITE_USER_MANAGEMENT_BASE" ]; then \
|
||||||
echo "ERROR: VITE_API_URL, VITE_BASE_API_URL, and VITE_USER_MANAGEMENT_BASE must all be set" && \
|
echo "ERROR: VITE_API_URL, VITE_BASE_API_URL, and VITE_USER_MANAGEMENT_BASE must all be set" && \
|
||||||
|
|||||||
248
pnpm-lock.yaml
generated
248
pnpm-lock.yaml
generated
@@ -241,6 +241,9 @@ importers:
|
|||||||
'@mantine/hooks':
|
'@mantine/hooks':
|
||||||
specifier: ^9.3.0
|
specifier: ^9.3.0
|
||||||
version: 9.3.0(react@19.2.6)
|
version: 9.3.0(react@19.2.6)
|
||||||
|
'@posthog/react':
|
||||||
|
specifier: ^1.10.3
|
||||||
|
version: 1.10.3(@types/react@18.3.31)(posthog-js@1.400.1)(react@19.2.6)
|
||||||
'@radix-ui/react-accordion':
|
'@radix-ui/react-accordion':
|
||||||
specifier: ^1.2.13
|
specifier: ^1.2.13
|
||||||
version: 1.2.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
version: 1.2.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||||
@@ -409,6 +412,9 @@ importers:
|
|||||||
pdf-lib:
|
pdf-lib:
|
||||||
specifier: ^1.17.1
|
specifier: ^1.17.1
|
||||||
version: 1.17.1
|
version: 1.17.1
|
||||||
|
posthog-js:
|
||||||
|
specifier: ^1.400.1
|
||||||
|
version: 1.400.1
|
||||||
prop-types:
|
prop-types:
|
||||||
specifier: ^15.8.1
|
specifier: ^15.8.1
|
||||||
version: 15.8.1
|
version: 15.8.1
|
||||||
@@ -566,12 +572,15 @@ importers:
|
|||||||
'@mantine/hooks':
|
'@mantine/hooks':
|
||||||
specifier: ^9.3.0
|
specifier: ^9.3.0
|
||||||
version: 9.3.0(react@19.2.6)
|
version: 9.3.0(react@19.2.6)
|
||||||
|
'@posthog/react':
|
||||||
|
specifier: ^1.10.3
|
||||||
|
version: 1.10.3(@types/react@18.3.31)(posthog-js@1.400.1)(react@19.2.6)
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: ^5.59.0
|
specifier: ^5.59.0
|
||||||
version: 5.101.0(react@19.2.6)
|
version: 5.101.0(react@19.2.6)
|
||||||
'@tria-plc/iamui':
|
'@tria-plc/iamui':
|
||||||
specifier: file:../../../local-packages/tria-plc-iamui-0.1.1.tgz
|
specifier: file:../../../local-packages/tria-plc-iamui-0.1.1.tgz
|
||||||
version: file:local-packages/tria-plc-iamui-0.1.1.tgz(a5d0bdee55164ae56064fb273b530e00)
|
version: file:local-packages/tria-plc-iamui-0.1.1.tgz(0ce39b7e349029277dcd938d06eeb0f7)
|
||||||
'@vis.gl/react-google-maps':
|
'@vis.gl/react-google-maps':
|
||||||
specifier: ^1.8.3
|
specifier: ^1.8.3
|
||||||
version: 1.8.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
version: 1.8.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||||
@@ -590,6 +599,9 @@ importers:
|
|||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^1.14.0
|
specifier: ^1.14.0
|
||||||
version: 1.17.0(react@19.2.6)
|
version: 1.17.0(react@19.2.6)
|
||||||
|
posthog-js:
|
||||||
|
specifier: ^1.400.1
|
||||||
|
version: 1.400.1
|
||||||
radix-ui:
|
radix-ui:
|
||||||
specifier: ^1.4.3
|
specifier: ^1.4.3
|
||||||
version: 1.5.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
version: 1.5.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||||
@@ -3125,6 +3137,22 @@ packages:
|
|||||||
'@popperjs/core@2.11.8':
|
'@popperjs/core@2.11.8':
|
||||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||||
|
|
||||||
|
'@posthog/core@1.41.1':
|
||||||
|
resolution: {integrity: sha512-lKjPdeawDSvRhHnP14RwTSI5CofuyluhG3ISHRa+Kj6PyfSrEUyIkoVOpYWicFGgWikeaJCZzFQpo7ngHt9BcA==}
|
||||||
|
|
||||||
|
'@posthog/react@1.10.3':
|
||||||
|
resolution: {integrity: sha512-Qu//fGQmVlX0B9kTA3LLg67e7AYLEmeuA0Bf1qSyUM0uUILcRQGjQezhNQPLYSTakOqvXEnl6fM2iQBF6Toxrw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '>=16.8.0'
|
||||||
|
posthog-js: '>=1.257.2'
|
||||||
|
react: '>=16.8.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@posthog/types@1.394.0':
|
||||||
|
resolution: {integrity: sha512-ifQ7p8o8hoHErlJmpzCFzHQcuRam0vXk8LBVhBu4BlPYP6S0tog4FSAFItnI/nwN6cHZI0WFQilr7sIqQa7Flg==}
|
||||||
|
|
||||||
'@prisma/client@6.19.3':
|
'@prisma/client@6.19.3':
|
||||||
resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==}
|
resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==}
|
||||||
engines: {node: '>=18.18'}
|
engines: {node: '>=18.18'}
|
||||||
@@ -7050,6 +7078,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||||
engines: {node: ^12.20 || >= 14.13}
|
engines: {node: ^12.20 || >= 14.13}
|
||||||
|
|
||||||
|
fflate@0.4.8:
|
||||||
|
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
|
||||||
|
|
||||||
fflate@0.8.3:
|
fflate@0.8.3:
|
||||||
resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==}
|
resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==}
|
||||||
|
|
||||||
@@ -9498,10 +9529,21 @@ packages:
|
|||||||
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
posthog-js@1.400.1:
|
||||||
|
resolution: {integrity: sha512-NGfzNwTu+VBw4FekgYs/aQbEkTFkvmpTFUKDGZw/9K6R/sG2WyuLsnnXySRcNH8RMki0Io8v9flNATrrTfmT+Q==}
|
||||||
|
|
||||||
powershell-utils@0.1.0:
|
powershell-utils@0.1.0:
|
||||||
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
|
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
preact@10.29.7:
|
||||||
|
resolution: {integrity: sha512-DCHYrK/B10yUD3ZjLfhZ3WIE/9Vf9VFUODcRE2dRomTYDpJk6z6L9wecSfhfE6M9ZTHUdyQkoC46arIDhEV84Q==}
|
||||||
|
peerDependencies:
|
||||||
|
preact-render-to-string: '>=5'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
preact-render-to-string:
|
||||||
|
optional: true
|
||||||
|
|
||||||
prelude-ls@1.2.1:
|
prelude-ls@1.2.1:
|
||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -9601,6 +9643,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==}
|
resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
|
query-selector-shadow-dom@1.0.1:
|
||||||
|
resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==}
|
||||||
|
|
||||||
query-string@7.1.3:
|
query-string@7.1.3:
|
||||||
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
|
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -11478,6 +11523,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
web-vitals@5.3.0:
|
||||||
|
resolution: {integrity: sha512-q6LWsLatGYZp5VGBIOvbTj6JBV2nOmC8KvWztXBmwJcfFAzhwKwbOxhUH306XY3CcaZDUlSmSuNPBsCn0bFu+g==}
|
||||||
|
|
||||||
webdriver-bidi-protocol@0.4.1:
|
webdriver-bidi-protocol@0.4.1:
|
||||||
resolution: {integrity: sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==}
|
resolution: {integrity: sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==}
|
||||||
|
|
||||||
@@ -13696,6 +13744,19 @@ snapshots:
|
|||||||
|
|
||||||
'@popperjs/core@2.11.8': {}
|
'@popperjs/core@2.11.8': {}
|
||||||
|
|
||||||
|
'@posthog/core@1.41.1':
|
||||||
|
dependencies:
|
||||||
|
'@posthog/types': 1.394.0
|
||||||
|
|
||||||
|
'@posthog/react@1.10.3(@types/react@18.3.31)(posthog-js@1.400.1)(react@19.2.6)':
|
||||||
|
dependencies:
|
||||||
|
posthog-js: 1.400.1
|
||||||
|
react: 19.2.6
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 18.3.31
|
||||||
|
|
||||||
|
'@posthog/types@1.394.0': {}
|
||||||
|
|
||||||
'@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)':
|
'@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
prisma: 6.19.3(typescript@5.9.3)
|
prisma: 6.19.3(typescript@5.9.3)
|
||||||
@@ -16092,130 +16153,6 @@ snapshots:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
- vite
|
- vite
|
||||||
|
|
||||||
'@tria-plc/iamui@file:local-packages/tria-plc-iamui-0.1.1.tgz(a5d0bdee55164ae56064fb273b530e00)':
|
|
||||||
dependencies:
|
|
||||||
'@emotion/react': 11.14.0(@types/react@18.3.31)(react@19.2.6)
|
|
||||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.31)(react@19.2.6))(@types/react@18.3.31)(react@19.2.6)
|
|
||||||
'@hookform/resolvers': 5.4.0(react-hook-form@7.77.0(react@19.2.6))
|
|
||||||
'@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6)
|
|
||||||
'@mantine/charts': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(recharts@3.8.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1))
|
|
||||||
'@mantine/core': 7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@mantine/dates': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@mantine/hooks': 7.17.8(react@19.2.6)
|
|
||||||
'@mantine/notifications': 7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-accordion': 1.2.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-alert-dialog': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-avatar': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-checkbox': 1.3.4(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-collapsible': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-context-menu': 2.3.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-dialog': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-dropdown-menu': 2.1.17(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-hover-card': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-label': 2.1.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-navigation-menu': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-popover': 1.1.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-progress': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-radio-group': 1.4.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-scroll-area': 1.2.11(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-select': 2.3.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-separator': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-slot': 1.2.5(@types/react@18.3.31)(react@19.2.6)
|
|
||||||
'@radix-ui/react-switch': 1.3.0(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-tabs': 1.1.14(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-toast': 1.2.16(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@radix-ui/react-tooltip': 1.2.9(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@react-pdf/renderer': 4.5.1(react@19.2.6)
|
|
||||||
'@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@18.3.31)(react@19.2.6)(redux@5.0.1))(react@19.2.6)
|
|
||||||
'@tabler/icons-react': 3.44.0(react@19.2.6)
|
|
||||||
'@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.13.1)(lightningcss@1.32.0)(terser@5.48.0))
|
|
||||||
'@tanstack/react-query': 5.101.0(react@19.2.6)
|
|
||||||
'@tanstack/react-query-devtools': 5.101.0(@tanstack/react-query@5.101.0(react@19.2.6))(react@19.2.6)
|
|
||||||
'@tanstack/react-table': 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
'@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.3)
|
|
||||||
'@types/dompurify': 3.2.0
|
|
||||||
'@types/node': 24.13.1
|
|
||||||
'@types/tinymce': 4.6.9
|
|
||||||
axios: 1.17.0
|
|
||||||
class-variance-authority: 0.7.1
|
|
||||||
clsx: 2.1.1
|
|
||||||
cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
date-fns: 3.6.0
|
|
||||||
dayjs: 1.11.21
|
|
||||||
dompurify: 3.4.8
|
|
||||||
ethiopian-calendar-date-converter: 2.1.6
|
|
||||||
ethiopian-calendar-new: 1.1.0
|
|
||||||
file-type: 18.7.0
|
|
||||||
framer-motion: 12.40.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
html2canvas: 1.4.1
|
|
||||||
i18next: 25.10.10(typescript@5.9.3)
|
|
||||||
i18next-browser-languagedetector: 8.2.1
|
|
||||||
jquery: 3.7.1
|
|
||||||
js-cookie: 3.0.8
|
|
||||||
jspdf: 3.0.4
|
|
||||||
lodash: 4.18.1
|
|
||||||
lucide-react: 0.513.0(react@19.2.6)
|
|
||||||
mantine-react-table: 2.0.0-beta.9(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/dates@7.17.8(@mantine/core@7.17.8(@mantine/hooks@7.17.8(react@19.2.6))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@7.17.8(react@19.2.6))(@tabler/icons-react@3.44.0(react@19.2.6))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
mui-ethiopian-datepicker: 0.3.2(4b3af212eafdf0059f009b005d7e343d)
|
|
||||||
next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
path: 0.12.7
|
|
||||||
pdf-lib: 1.17.1
|
|
||||||
qs: 6.15.2
|
|
||||||
react: 19.2.6
|
|
||||||
react-cookie: 8.1.2(@types/react@18.3.31)(react@19.2.6)
|
|
||||||
react-css-nocode-editor: 1.0.13(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)
|
|
||||||
react-day-picker: 8.10.2(date-fns@3.6.0)(react@19.2.6)
|
|
||||||
react-dom: 19.2.6(react@19.2.6)
|
|
||||||
react-dropzone: 14.4.1(react@19.2.6)
|
|
||||||
react-hook-form: 7.77.0(react@19.2.6)
|
|
||||||
react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3)
|
|
||||||
react-icons: 5.6.0(react@19.2.6)
|
|
||||||
react-image-crop: 11.0.10(react@19.2.6)
|
|
||||||
react-intersection-observer: 9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
react-pdf: 10.4.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@19.2.6))(react@19.2.6)
|
|
||||||
react-redux: 9.3.0(@types/react@18.3.31)(react@19.2.6)(redux@5.0.1)
|
|
||||||
react-resizable-panels: 3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
react-router-dom: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.31)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
recharts: 3.8.1(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1)
|
|
||||||
rollup-plugin-visualizer: 7.0.1(rollup@4.61.1)
|
|
||||||
socket.io-client: 4.8.3
|
|
||||||
sonner: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
tailwind-merge: 3.6.0
|
|
||||||
tailwind-scrollbar-hide: 4.0.0(tailwindcss@4.3.0)
|
|
||||||
tailwindcss: 4.3.0
|
|
||||||
tailwindcss-animate: 1.0.7(tailwindcss@4.3.0)
|
|
||||||
tinymce: 7.9.3
|
|
||||||
url: 0.11.4
|
|
||||||
vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
|
||||||
xlsx: 0.18.5
|
|
||||||
zod: 3.25.76
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@babel/core'
|
|
||||||
- '@emotion/is-prop-valid'
|
|
||||||
- '@mui/icons-material'
|
|
||||||
- '@mui/material'
|
|
||||||
- '@mui/x-date-pickers'
|
|
||||||
- '@types/prop-types'
|
|
||||||
- '@types/react'
|
|
||||||
- '@types/react-dom'
|
|
||||||
- bufferutil
|
|
||||||
- debug
|
|
||||||
- pdfjs-dist
|
|
||||||
- prop-types
|
|
||||||
- react-is
|
|
||||||
- react-native
|
|
||||||
- redux
|
|
||||||
- rolldown
|
|
||||||
- rollup
|
|
||||||
- supports-color
|
|
||||||
- typescript
|
|
||||||
- utf-8-validate
|
|
||||||
- vite
|
|
||||||
|
|
||||||
'@ts-morph/common@0.27.0':
|
'@ts-morph/common@0.27.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-glob: 3.3.3
|
fast-glob: 3.3.3
|
||||||
@@ -17402,16 +17339,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
babel-plugin-styled-components@2.3.0(styled-components@5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6))(supports-color@5.5.0):
|
|
||||||
dependencies:
|
|
||||||
'@babel/helper-annotate-as-pure': 7.29.7
|
|
||||||
'@babel/helper-module-imports': 7.29.7(supports-color@5.5.0)
|
|
||||||
'@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7)
|
|
||||||
picomatch: 4.0.4
|
|
||||||
styled-components: 5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
babel-polyfill@6.26.0:
|
babel-polyfill@6.26.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
babel-runtime: 6.26.0
|
babel-runtime: 6.26.0
|
||||||
@@ -18015,8 +17942,7 @@ snapshots:
|
|||||||
|
|
||||||
core-js@2.6.12: {}
|
core-js@2.6.12: {}
|
||||||
|
|
||||||
core-js@3.49.0:
|
core-js@3.49.0: {}
|
||||||
optional: true
|
|
||||||
|
|
||||||
core-util-is@1.0.3: {}
|
core-util-is@1.0.3: {}
|
||||||
|
|
||||||
@@ -19202,6 +19128,8 @@ snapshots:
|
|||||||
node-domexception: 1.0.0
|
node-domexception: 1.0.0
|
||||||
web-streams-polyfill: 3.3.3
|
web-streams-polyfill: 3.3.3
|
||||||
|
|
||||||
|
fflate@0.4.8: {}
|
||||||
|
|
||||||
fflate@0.8.3: {}
|
fflate@0.8.3: {}
|
||||||
|
|
||||||
figures@1.7.0:
|
figures@1.7.0:
|
||||||
@@ -21856,8 +21784,23 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
xtend: 4.0.2
|
xtend: 4.0.2
|
||||||
|
|
||||||
|
posthog-js@1.400.1:
|
||||||
|
dependencies:
|
||||||
|
'@posthog/core': 1.41.1
|
||||||
|
'@posthog/types': 1.394.0
|
||||||
|
core-js: 3.49.0
|
||||||
|
dompurify: 3.4.8
|
||||||
|
fflate: 0.4.8
|
||||||
|
preact: 10.29.7
|
||||||
|
query-selector-shadow-dom: 1.0.1
|
||||||
|
web-vitals: 5.3.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- preact-render-to-string
|
||||||
|
|
||||||
powershell-utils@0.1.0: {}
|
powershell-utils@0.1.0: {}
|
||||||
|
|
||||||
|
preact@10.29.7: {}
|
||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier@3.8.3: {}
|
prettier@3.8.3: {}
|
||||||
@@ -21981,6 +21924,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.1.0
|
side-channel: 1.1.0
|
||||||
|
|
||||||
|
query-selector-shadow-dom@1.0.1: {}
|
||||||
|
|
||||||
query-string@7.1.3:
|
query-string@7.1.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
decode-uri-component: 0.2.2
|
decode-uri-component: 0.2.2
|
||||||
@@ -22173,15 +22118,6 @@ snapshots:
|
|||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- react-is
|
- react-is
|
||||||
|
|
||||||
react-css-nocode-editor@1.0.13(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6):
|
|
||||||
dependencies:
|
|
||||||
react: 19.2.6
|
|
||||||
react-dom: 19.2.6(react@19.2.6)
|
|
||||||
styled-components: 5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@babel/core'
|
|
||||||
- react-is
|
|
||||||
|
|
||||||
react-day-picker@8.10.2(date-fns@3.6.0)(react@19.2.6):
|
react-day-picker@8.10.2(date-fns@3.6.0)(react@19.2.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
date-fns: 3.6.0
|
date-fns: 3.6.0
|
||||||
@@ -23371,24 +23307,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
|
|
||||||
styled-components@5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6):
|
|
||||||
dependencies:
|
|
||||||
'@babel/helper-module-imports': 7.29.7(supports-color@5.5.0)
|
|
||||||
'@babel/traverse': 7.29.7(supports-color@5.5.0)
|
|
||||||
'@emotion/is-prop-valid': 1.4.0
|
|
||||||
'@emotion/stylis': 0.8.5
|
|
||||||
'@emotion/unitless': 0.7.5
|
|
||||||
babel-plugin-styled-components: 2.3.0(styled-components@5.3.11(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6))(supports-color@5.5.0)
|
|
||||||
css-to-react-native: 3.2.0
|
|
||||||
hoist-non-react-statics: 3.3.2
|
|
||||||
react: 19.2.6
|
|
||||||
react-dom: 19.2.6(react@19.2.6)
|
|
||||||
react-is: 19.2.7
|
|
||||||
shallowequal: 1.1.0
|
|
||||||
supports-color: 5.5.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@babel/core'
|
|
||||||
|
|
||||||
styled-jsx@5.1.1(babel-plugin-macros@3.1.0)(react@18.3.1):
|
styled-jsx@5.1.1(babel-plugin-macros@3.1.0)(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
client-only: 0.0.1
|
client-only: 0.0.1
|
||||||
@@ -24334,6 +24252,8 @@ snapshots:
|
|||||||
|
|
||||||
web-streams-polyfill@3.3.3: {}
|
web-streams-polyfill@3.3.3: {}
|
||||||
|
|
||||||
|
web-vitals@5.3.0: {}
|
||||||
|
|
||||||
webdriver-bidi-protocol@0.4.1: {}
|
webdriver-bidi-protocol@0.4.1: {}
|
||||||
|
|
||||||
webidl-conversions@7.0.0: {}
|
webidl-conversions@7.0.0: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user