feat(analytics): persona logging upgrade and Sentry system config
Add client-logging SDK, expanded event taxonomy, API observability, admin domain events UI, and move SENTRY_DSN to HQ system settings with @sentry/node bootstrap after config preload. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
"lint": "echo ok"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dukang/client-logging": "workspace:*",
|
||||
"@dukang/shared-types": "workspace:*",
|
||||
"@dukang/shared-ui": "workspace:*",
|
||||
"@dukang/weixin-sdk": "workspace:*",
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { createPartnerTracker } from '@dukang/client-logging';
|
||||
import { apiBase } from './api';
|
||||
|
||||
const tracker = createPartnerTracker({
|
||||
apiBase,
|
||||
clientApp: 'PARTNER_H5',
|
||||
getToken: () => localStorage.getItem('partnerAccessToken'),
|
||||
});
|
||||
|
||||
export function trackPartner(eventName: string, params?: Record<string, unknown>) {
|
||||
tracker.track(eventName, params);
|
||||
}
|
||||
|
||||
export function trackPartnerPageView(eventName: string, params?: Record<string, unknown>) {
|
||||
tracker.trackPageView(eventName, params);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { trackPartnerPageView } from './analytics';
|
||||
|
||||
export function usePartnerPageView(eventName: string, params?: Record<string, unknown>) {
|
||||
const fired = useRef(false);
|
||||
useEffect(() => {
|
||||
if (fired.current) return;
|
||||
fired.current = true;
|
||||
trackPartnerPageView(eventName, params);
|
||||
}, [eventName, params]);
|
||||
}
|
||||
@@ -5,11 +5,16 @@ import { getRouterBasename } from '@dukang/weixin-sdk';
|
||||
import App from './App';
|
||||
import { PartnerSessionProvider } from './contexts/PartnerSessionContext';
|
||||
import { PartnerToastProvider } from './contexts/PartnerToastContext';
|
||||
import { installClientErrorReporting } from './lib/client-error';
|
||||
import { installClientErrorReporting } from '@dukang/client-logging';
|
||||
import { apiBase } from './lib/api';
|
||||
import './styles.css';
|
||||
import './styles/legal.css';
|
||||
|
||||
installClientErrorReporting();
|
||||
installClientErrorReporting({
|
||||
apiBase,
|
||||
clientApp: 'PARTNER_H5',
|
||||
getToken: () => localStorage.getItem('partnerAccessToken'),
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
|
||||
@@ -5,6 +5,7 @@ import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
|
||||
import type { PartnerBillDto } from '@dukang/shared-types';
|
||||
import { isLoggedIn, request } from '../lib/api';
|
||||
import { toastError, toastSuccess } from '../lib/toast';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
function fmtMoney(n: number) {
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
@@ -25,6 +26,7 @@ function canConfirm(status: string) {
|
||||
}
|
||||
|
||||
export default function BillsPage() {
|
||||
usePartnerPageView('partner_bills_view');
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const [bills, setBills] = useState<PartnerBillDto[]>([]);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import type { PartnerLeaderboardEntry } from '@dukang/shared-types';
|
||||
import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
import { isLoggedIn, request } from '../lib/api';
|
||||
import { fetchPartnerLeaderboard } from '../lib/leaderboard';
|
||||
import {
|
||||
@@ -137,6 +138,7 @@ function LeaderboardPreview({ entries }: { entries: PartnerLeaderboardEntry[] })
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
usePartnerPageView('partner_home_view');
|
||||
const navigate = useNavigate();
|
||||
const { account } = usePartnerSession();
|
||||
const navKind = getPartnerNavKind(account);
|
||||
|
||||
@@ -6,6 +6,7 @@ import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
|
||||
import { fetchPartnerLeaderboard } from '../lib/leaderboard';
|
||||
import { usePartnerSession } from '../contexts/PartnerSessionContext';
|
||||
import { isPrimaryAccount } from '../lib/partnerAccess';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
const PERIOD_TABS: { key: PartnerLeaderboardPeriod; label: string }[] = [
|
||||
{ key: 'month', label: '本月' },
|
||||
@@ -26,6 +27,7 @@ function periodSubLabel(period: PartnerLeaderboardPeriod): string {
|
||||
}
|
||||
|
||||
export default function LeaderboardPage() {
|
||||
usePartnerPageView('partner_leaderboard_view');
|
||||
const navigate = useNavigate();
|
||||
const { account } = usePartnerSession();
|
||||
const showStaffFab = isPrimaryAccount(account);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
||||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||||
import { request } from '../lib/api';
|
||||
import { toastError, toastSuccess } from '../lib/toast';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
const TIMELINE = [
|
||||
{ key: 'confirm', label: '待确认' },
|
||||
@@ -36,6 +37,7 @@ function canShip(status: string) {
|
||||
|
||||
export default function OrderDetailPage() {
|
||||
const { id } = useParams();
|
||||
usePartnerPageView('partner_order_detail_view', id ? { orderId: id } : undefined);
|
||||
const navigate = useNavigate();
|
||||
const [order, setOrder] = useState<Record<string, unknown> | null>(null);
|
||||
const [shipping, setShipping] = useState(false);
|
||||
|
||||
@@ -5,6 +5,7 @@ import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
|
||||
import { isLoggedIn, request } from '../lib/api';
|
||||
import { usePartnerSession } from '../contexts/PartnerSessionContext';
|
||||
import { hasWarehouseAccess } from '../lib/partnerAccess';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
type DateFilter = 'today' | '7d' | '30d';
|
||||
type StatusFilter = 'ALL' | 'PENDING_SHIP' | 'SHIPPING' | 'COMPLETED' | 'ABNORMAL';
|
||||
@@ -44,6 +45,7 @@ type OrdersResponse = {
|
||||
};
|
||||
|
||||
export default function OrderListPage({ tabRoot = false }: OrderListPageProps) {
|
||||
usePartnerPageView('partner_order_list_view');
|
||||
const navigate = useNavigate();
|
||||
const { account } = usePartnerSession();
|
||||
const warehouseOk = hasWarehouseAccess(account);
|
||||
|
||||
@@ -24,6 +24,7 @@ import type {
|
||||
ProxyOrderPayResponse,
|
||||
ProxyPayMethod,
|
||||
} from '@dukang/shared-types';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
function fmtMoney(n: number) {
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
@@ -46,6 +47,7 @@ function initialDraft(): ProxyOrderDraft {
|
||||
}
|
||||
|
||||
export default function ProxyOrderPage() {
|
||||
usePartnerPageView('partner_proxy_order_view');
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const draft0 = useMemo(() => initialDraft(), []);
|
||||
|
||||
@@ -9,8 +9,10 @@ import {
|
||||
type PartnerStaffItem,
|
||||
} from '@dukang/shared-types';
|
||||
import { deletePartnerStaff, listPartnerStaff, updatePartnerStaff } from '../lib/staff';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
export default function StaffListPage() {
|
||||
usePartnerPageView('partner_staff_list_view');
|
||||
const navigate = useNavigate();
|
||||
const [staff, setStaff] = useState<PartnerStaffItem[]>([]);
|
||||
const [q, setQ] = useState('');
|
||||
|
||||
@@ -20,6 +20,7 @@ import { isWechatEnv, weixinSdk } from '../lib/weixin';
|
||||
import { usePartnerSession } from '../contexts/PartnerSessionContext';
|
||||
|
||||
import TencentLocPickerOverlay from '../components/TencentLocPickerOverlay';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
import {
|
||||
|
||||
@@ -78,6 +79,8 @@ function isPhoneValidationMessage(message: string) {
|
||||
|
||||
export default function StoreCreatePage() {
|
||||
|
||||
usePartnerPageView('partner_store_create_view');
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { account } = usePartnerSession();
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
storeStatusPillClass,
|
||||
type StoreStatusValue,
|
||||
} from '../lib/storeStatus';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
const STATUS_OPTIONS: StoreStatusValue[] = ['OPEN', 'PAUSED', 'CLOSED'];
|
||||
|
||||
@@ -33,6 +34,7 @@ function uniqueEnvUrls(urls: string[]): string[] {
|
||||
|
||||
export default function StoreDetailPage() {
|
||||
const { id } = useParams();
|
||||
usePartnerPageView('partner_store_detail_view', id ? { storeId: id } : undefined);
|
||||
const navigate = useNavigate();
|
||||
const { account } = usePartnerSession();
|
||||
const canMutate = canManagePartnerStore(account);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
storeStatusPillClass,
|
||||
type StoreStatusValue,
|
||||
} from '../lib/storeStatus';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
type StatusFilter = 'ALL' | StoreStatusValue | 'PENDING_AUDIT' | 'REJECTED';
|
||||
|
||||
@@ -26,6 +27,7 @@ const FILTERS: { key: StatusFilter; label: string }[] = [
|
||||
];
|
||||
|
||||
export default function StoreListPage() {
|
||||
usePartnerPageView('partner_store_list_view');
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { account } = usePartnerSession();
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { PartnerWeeklyReportResponse } from '@dukang/shared-types';
|
||||
import PageHeader from '@dukang/shared-ui/PageHeader';
|
||||
import PullToRefresh from '@dukang/shared-ui/PullToRefresh';
|
||||
import { fetchPartnerWeeklyReport } from '../lib/weeklyReport';
|
||||
import { usePartnerPageView } from '../lib/usePageView';
|
||||
|
||||
function fmtMoney(n: number) {
|
||||
return n.toLocaleString('zh-CN', { minimumFractionDigits: 0, maximumFractionDigits: 0 });
|
||||
@@ -15,6 +16,7 @@ function fmtGrowth(n: number) {
|
||||
}
|
||||
|
||||
export default function WeeklyReportPage() {
|
||||
usePartnerPageView('partner_weekly_report_view');
|
||||
const navigate = useNavigate();
|
||||
const [selectedStart, setSelectedStart] = useState<string | undefined>();
|
||||
const [data, setData] = useState<PartnerWeeklyReportResponse | null>(null);
|
||||
|
||||
Reference in New Issue
Block a user