@verifiedinc-public/shared-ui-elements 12.26.0 → 12.27.0
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/components/chart/BillableEventsProductTable/BillableEventsProductTable.mjs +1 -1
- package/dist/components/chart/BillableEventsProductTable/BillableEventsProductTableDataMapper.d.ts +1 -0
- package/dist/components/chart/BillableEventsProductTable/BillableEventsProductTableDataMapper.mjs +1 -1
- package/dist/components/chart/BillableEventsTable/BillableEventsTable.mjs +1 -1
- package/dist/components/chart/BillableEventsTable/BillableEventsTable.types.d.ts +12 -0
- package/dist/components/chart/BillableEventsTable/BillableEventsTableDataMapper.d.ts +1 -0
- package/dist/components/chart/BillableEventsTable/BillableEventsTableDataMapper.mjs +1 -1
- package/dist/components/chart/BillableEventsTable/billableEventsExportRecord.d.ts +3 -1
- package/dist/components/chart/BillableEventsTable/billableEventsExportRecord.mjs +1 -1
- package/dist/components/chart/BillableEventsTable/internalBrandColumn.d.ts +7 -0
- package/dist/components/chart/BillableEventsTable/internalBrandColumn.mjs +1 -0
- package/dist/components/chart/BillableEventsTable/useBillableSort.hook.d.ts +2 -1
- package/dist/components/chart/BillableEventsTable/useBillableSort.hook.mjs +1 -1
- package/dist/components/chart/ConversionOverTimeChart/index.d.ts +5 -0
- package/dist/components/chart/ConversionOverTimeChart/index.mjs +1 -1
- package/dist/components/chart/InternalBrandNameToggle/index.d.ts +8 -0
- package/dist/components/chart/InternalBrandNameToggle/index.mjs +1 -0
- package/dist/components/chart/SeriesPercentageChartLegend/index.mjs +1 -1
- package/dist/components/chart/SynchronizedMetricsChart/SynchronizedMetricsChart.d.ts +1 -1
- package/dist/components/chart/SynchronizedMetricsChart/SynchronizedMetricsChart.map.d.ts +7 -0
- package/dist/components/chart/SynchronizedMetricsChart/SynchronizedMetricsChart.map.mjs +1 -1
- package/dist/components/chart/SynchronizedMetricsChart/SynchronizedMetricsChart.mjs +1 -1
- package/dist/components/chart/SynchronizedMetricsChart/SynchronizedMetricsChart.types.d.ts +5 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{Box as
|
|
1
|
+
"use strict";import{Box as E}from"@mui/material";import{useMemo as N}from"react";import{DataTable as S}from"../../DataTable/DataTable.mjs";import{EmptyChartSection as U}from"../EmptyChartSection.mjs";import{LoadingChartSection as v}from"../LoadingChartSection.mjs";import{BILLABLE_PRODUCTS as p}from"../BillableEventsTable/BillableEventsTable.types.mjs";import{billableEventsExportRecord as I}from"../BillableEventsTable/billableEventsExportRecord.mjs";import{formatBillableMetric as F}from"../BillableEventsTable/format.mjs";import{useBillableSort as L}from"../BillableEventsTable/useBillableSort.hook.mjs";import{internalBrandColumn as R,INTERNAL_BRAND_HIDDEN as w,internalBrandName as T,INTERNAL_BRAND_COLUMN_ID as _}from"../BillableEventsTable/internalBrandColumn.mjs";import{CopyableUuid as k}from"../../CopyableUuid/index.mjs";import{jsx as e}from"react/jsx-runtime";const A={brand:r=>r.brand,[_]:T},P={align:"right"};function K({row:r}){return e(k,{uuid:r.original.brandUuid,label:"Brand UUID",variant:"button",head:6,tail:0,mono:!1,iconSx:{color:"success.main"},typographyProps:{variant:"inherit",color:"inherit"}})}const M=({data:r,isLoading:b,isFetching:g,product:i,columnSlots:t,showInternalBrandColumn:l=!1,enableExport:d=!1,enableJsonExport:h=!1,exportFilename:f,cspNonce:C})=>{const{sortKey:m,sortDir:c,setSort:u,sortedData:B}=L(r,A,"brand"),y=N(()=>{var n;const a=((n=p.find(o=>o.product===i))==null?void 0:n.columns)??[];return[{id:"brand",accessorKey:"brand",header:"Brand Name",enableSorting:!0,enableColumnFilter:!1},...l?[R()]:[],{id:"brandUuid",accessorKey:"brandUuid",header:"Brand UUID",enableColumnFilter:!1,cell:K},...a.map(o=>({id:o.key,accessorFn:s=>s.metrics[o.key]??0,header:o.label,enableSorting:!0,sortDescFirst:!1,enableColumnFilter:!1,meta:P,cell:({row:s})=>t!=null&&t[o.key]?t[o.key](s.original):F(s.original.metrics[o.key])}))]},[i,t,l]),x=[{id:m,desc:c==="desc"}],D=n=>{const[a]=n;a?u(a.id,a.desc?"desc":"asc"):u(m,c==="asc"?"desc":"asc")};return!(r!=null&&r.length)&&b?e(v,{}):r!=null&&r.length?e(E,{sx:{opacity:g?.4:1},children:e(S,{data:B,columns:y,getRowId:n=>n.brandUuid,manualSorting:!0,sorting:x,onSortingChange:D,disablePagination:!0,pinFirstColumn:!1,showToolbar:d||l,initialColumnVisibility:w,enableExport:d,enableJsonExport:h,exportFilename:f,exportRecord:n=>{var a;return I(n,{visibleProducts:[i],topLevelColumns:((a=p.find(o=>o.product===i))==null?void 0:a.columns)??[],showCustomerColumn:!1,showInternalBrandColumn:l})},cspNonce:C})}):e(U,{})};export{M as BillableEventsProductTable};
|
package/dist/components/chart/BillableEventsProductTable/BillableEventsProductTableDataMapper.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{BILLABLE_PRODUCTS as b}from"../BillableEventsTable/BillableEventsTable.types.mjs";const f=({product:s,data:c,brands:u})=>{const
|
|
1
|
+
"use strict";import{BILLABLE_PRODUCTS as b}from"../BillableEventsTable/BillableEventsTable.types.mjs";const f=({product:s,data:c,brands:u})=>{const i=b.find(r=>r.product===s);if(!i)return[];const a=new Map;for(const r of c){const n=u.find(e=>e.brandUuid===r.brandUuid);if(!n||!r.interval)continue;const t=a.get(r.brandUuid),d=t?.metrics??{};for(const e of r.interval)for(const o of i.columns)d[o.key]=(d[o.key]??0)+(Number(e[o.metricKey])||0);t||a.set(r.brandUuid,{brandUuid:r.brandUuid,brand:n.brandName,internalBrand:n.internalBrandName||n.brandName,metrics:d,raw:r})}return Array.from(a.values())};export{f as mapBillableEventsProductTableData};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{Box as
|
|
1
|
+
"use strict";import{Box as A,TableRow as S,TableCell as v}from"@mui/material";import{flexRender as _}from"@tanstack/react-table";import{useState as j,useEffect as M,useMemo as y}from"react";import{DataTable as O}from"../../DataTable/DataTable.mjs";import{EmptyChartSection as J}from"../EmptyChartSection.mjs";import{LoadingChartSection as K}from"../LoadingChartSection.mjs";import{BillableProduct as V,BILLABLE_PRODUCTS as H}from"./BillableEventsTable.types.mjs";import{billableEventsExportRecord as $}from"./billableEventsExportRecord.mjs";import{BrandDetailsPanel as q}from"./BrandDetailsPanel.mjs";import{formatBillableMetric as z}from"./format.mjs";import{internalBrandColumn as G,INTERNAL_BRAND_HIDDEN as Q,internalBrandName as W,INTERNAL_BRAND_COLUMN_ID as X}from"./internalBrandColumn.mjs";import{useBillableSort as Y}from"./useBillableSort.hook.mjs";import{jsx as a,jsxs as Z,Fragment as ee}from"react/jsx-runtime";const oe={customerName:e=>e.customerName??"",brand:e=>e.brand,[X]:W},re={align:"right"},ne={id:"customerName",accessorFn:e=>e.customerName??"",header:"Customer Name",enableSorting:!0,enableColumnFilter:!1,cell:({row:e})=>e.original.customerName??"\u2014"};function D(e,i){return{id:e.key,accessorFn:l=>l.metrics[e.key]??0,header:e.label,enableSorting:!0,sortDescFirst:!1,enableColumnFilter:!1,meta:re,cell:({row:l})=>i!=null&&i[e.key]?i[e.key](l.original):z(l.original.metrics[e.key])}}const ae=({data:e,isLoading:i,isFetching:l,visibleProducts:p,onSortedDataChange:b,columnSlots:g,topLevelColumns:c=[],showCustomerColumn:s=!0,showInternalBrandColumn:d=!1,enableExport:C=!1,enableJsonExport:E=!1,exportFilename:U,cspNonce:w})=>{const{sortKey:f,sortDir:x,setSort:N,sortedData:h}=Y(e,oe,"brand"),[F,R]=j(null);M(()=>{b?.(h)},[h,b]);const I=y(()=>{const r=p??Object.values(V),t=new Set(c.map(o=>o.key));return[...s?[ne]:[],{id:"brand",accessorKey:"brand",header:"Brand Name",enableSorting:!0,enableColumnFilter:!1},...d?[G()]:[],...c.map(o=>D(o,g)),...H.filter(o=>r.includes(o.product)).map(o=>({product:o,columns:o.columns.filter(n=>!t.has(n.key))})).filter(({columns:o})=>o.length>0).map(({product:o,columns:n})=>({id:`product:${o.product}`,header:o.label,columns:n.map(m=>D(m,g))}))]},[p,c,s,d,g]),L=y(()=>[...s?[{header:"Customer UUID",value:r=>r.customerUuid??""}]:[],{header:"Brand UUID",value:r=>r.brandUuid}],[s]),P=[{id:f,desc:x==="desc"}],T=r=>{const[t]=r;t?N(t.id,t.desc?"desc":"asc"):N(f,x==="asc"?"desc":"asc")},k=({row:r,rowProps:t,getCellProps:o})=>{const n=r.original,m=F===n.brandUuid,B=r.getVisibleCells();return Z(ee,{children:[a(S,{...t,hover:!0,onClick:()=>R(m?null:n.brandUuid),sx:{cursor:"pointer","& > td":{borderBottom:m?"none":void 0}},children:B.map(u=>a(v,{...o(u),children:_(u.column.columnDef.cell,u.getContext())},u.id))}),m&&a(S,{children:a(v,{colSpan:B.length,sx:{py:0,px:0,borderTop:"none",bgcolor:"grey.50"},children:a(q,{brandUuid:n.brandUuid,customerUuid:s?n.customerUuid:void 0,challengePrompts:n.challengePrompts,providers:n.providers})})})]})};return!(e!=null&&e.length)&&i?a(K,{}):e!=null&&e.length?a(A,{sx:{opacity:l?.4:1},children:a(O,{data:h,columns:I,getRowId:r=>r.brandUuid,renderRow:k,manualSorting:!0,sorting:P,onSortingChange:T,disablePagination:!0,pinFirstColumn:!1,showToolbar:C||d,initialColumnVisibility:Q,enableExport:C,enableJsonExport:E,exportFilename:U,additionalExportColumns:L,exportRecord:r=>$(r,{visibleProducts:p,topLevelColumns:c,showCustomerColumn:s,showInternalBrandColumn:d}),cspNonce:w})}):a(J,{})};export{ae as BillableEventsTable};
|
|
@@ -29,6 +29,8 @@ export declare const BILLABLE_PRODUCTS: BillableProductConfig[];
|
|
|
29
29
|
export type BillableEventsTableRow = {
|
|
30
30
|
brandUuid: string;
|
|
31
31
|
brand: string;
|
|
32
|
+
/** The customer's own name for the brand, shown by the opt-in Internal Brand Name column. */
|
|
33
|
+
internalBrand?: string;
|
|
32
34
|
customerUuid?: string;
|
|
33
35
|
customerName?: string;
|
|
34
36
|
metrics: Record<string, number>;
|
|
@@ -61,6 +63,11 @@ export type BillableEventsTableProps = BillableEventsExportProps & {
|
|
|
61
63
|
* for views scoped to a single customer where the column would be redundant.
|
|
62
64
|
*/
|
|
63
65
|
showCustomerColumn?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Offer an Internal Brand Name column (rows' `internalBrand`) in Manage columns, hidden until
|
|
68
|
+
* the user picks it. Defaults to `false`.
|
|
69
|
+
*/
|
|
70
|
+
showInternalBrandColumn?: boolean;
|
|
64
71
|
};
|
|
65
72
|
export type BillableEventsProductTableProps = BillableEventsExportProps & {
|
|
66
73
|
data: BillableEventsTableRow[];
|
|
@@ -68,4 +75,9 @@ export type BillableEventsProductTableProps = BillableEventsExportProps & {
|
|
|
68
75
|
isFetching: boolean;
|
|
69
76
|
product: BillableProduct;
|
|
70
77
|
columnSlots?: Record<string, (row: BillableEventsTableRow) => React.ReactNode>;
|
|
78
|
+
/**
|
|
79
|
+
* Offer an Internal Brand Name column (rows' `internalBrand`) in Manage columns, hidden until
|
|
80
|
+
* the user picks it. Defaults to `false`.
|
|
81
|
+
*/
|
|
82
|
+
showInternalBrandColumn?: boolean;
|
|
71
83
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{BILLABLE_PRODUCTS as
|
|
1
|
+
"use strict";import{BILLABLE_PRODUCTS as f}from"./BillableEventsTable.types.mjs";const p=({productDataSets:u,brands:c})=>{var i;const o=new Map,d=new Map;for(const{product:a,data:s}of u){const r=f.find(n=>n.product===a);if(r)for(const n of s){if(!((i=n.interval)!=null&&i.length))continue;const e=o.get(n.brandUuid)??{};for(const t of r.columns){const l=n.interval.reduce((b,m)=>b+(Number(m[t.metricKey])||0),0);e[t.key]=(e[t.key]??0)+l}r.columns.some(t=>(e[t.key]??0)>0)&&!d.has(n.brandUuid)&&d.set(n.brandUuid,n),o.set(n.brandUuid,e)}}return Array.from(d.entries()).map(([a,s])=>{const r=c.find(n=>n.brandUuid===a);return r?{brandUuid:a,brand:r.brandName,internalBrand:r.internalBrandName||r.brandName,metrics:o.get(a)??{},raw:s}:null}).filter(a=>a!==null)};export{p as mapBillableEventsTableData};
|
|
@@ -5,11 +5,13 @@ interface BillableEventsExportRecordOptions {
|
|
|
5
5
|
/** Columns the table lifts out of their product group; written at the top level. */
|
|
6
6
|
topLevelColumns?: BillableEventColumn[];
|
|
7
7
|
showCustomerColumn?: boolean;
|
|
8
|
+
/** Adds the brand's internal name, when the table offers that column. */
|
|
9
|
+
showInternalBrandColumn?: boolean;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* A row as the JSON export writes it: the brand (and customer) as `{ name, uuid }`, then each
|
|
11
13
|
* product's event counts grouped under the product — rather than the row's internal shape (raw
|
|
12
14
|
* chart data, panel details).
|
|
13
15
|
*/
|
|
14
|
-
export declare function billableEventsExportRecord(row: BillableEventsTableRow, { visibleProducts, topLevelColumns, showCustomerColumn, }?: BillableEventsExportRecordOptions): Record<string, unknown>;
|
|
16
|
+
export declare function billableEventsExportRecord(row: BillableEventsTableRow, { visibleProducts, topLevelColumns, showCustomerColumn, showInternalBrandColumn, }?: BillableEventsExportRecordOptions): Record<string, unknown>;
|
|
15
17
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{BILLABLE_PRODUCTS as
|
|
1
|
+
"use strict";import{BILLABLE_PRODUCTS as c,BillableProduct as i}from"./BillableEventsTable.types.mjs";const d=e=>e.toLowerCase().replace(/_([a-z])/g,(o,n)=>n.toUpperCase()),p=e=>e.slice(e.indexOf("_")+1),l=(e,o)=>Object.fromEntries(o.map(n=>[p(n.key),e.metrics[n.key]??0]));function b(e,{visibleProducts:o=Object.values(i),topLevelColumns:n=[],showCustomerColumn:a=!0,showInternalBrandColumn:s=!1}={}){const u=new Set(n.map(r=>r.key)),m=c.filter(r=>o.includes(r.product)).map(r=>({key:d(r.product),columns:r.columns.filter(t=>!u.has(t.key))})).filter(({columns:r})=>r.length>0);return{...a?{customer:{name:e.customerName??null,uuid:e.customerUuid??null}}:{},brand:{name:e.brand,...s?{internalName:e.internalBrand||e.brand}:{},uuid:e.brandUuid},...l(e,n),...Object.fromEntries(m.map(({key:r,columns:t})=>[r,l(e,t)]))}}export{b as billableEventsExportRecord};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ColumnDef, VisibilityState } from '@tanstack/react-table';
|
|
2
|
+
import { BillableEventsTableRow } from './BillableEventsTable.types';
|
|
3
|
+
export declare const INTERNAL_BRAND_COLUMN_ID = "internalBrand";
|
|
4
|
+
export declare const INTERNAL_BRAND_HIDDEN: VisibilityState;
|
|
5
|
+
/** The customer's own name for the brand, falling back to the external name when unset. */
|
|
6
|
+
export declare const internalBrandName: (row: BillableEventsTableRow) => string;
|
|
7
|
+
export declare function internalBrandColumn<Row extends BillableEventsTableRow>(): ColumnDef<Row, unknown>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const n="internalBrand",e={[n]:!1},r=a=>a.internalBrand||a.brand;function t(){return{id:n,accessorFn:r,header:"Internal Brand Name",enableSorting:!0,enableColumnFilter:!1}}export{n as INTERNAL_BRAND_COLUMN_ID,e as INTERNAL_BRAND_HIDDEN,t as internalBrandColumn,r as internalBrandName};
|
|
@@ -2,7 +2,8 @@ type SortDirection = 'asc' | 'desc';
|
|
|
2
2
|
type WithMetrics = {
|
|
3
3
|
metrics: Record<string, number>;
|
|
4
4
|
} & Record<string, unknown>;
|
|
5
|
-
export
|
|
5
|
+
export type BillableSortValues<T> = Record<string, (row: T) => string | number>;
|
|
6
|
+
export declare function useBillableSort<T extends WithMetrics>(data: T[] | undefined, directValues: BillableSortValues<T>, initialSortKey: string): {
|
|
6
7
|
sortKey: string;
|
|
7
8
|
sortDir: SortDirection;
|
|
8
9
|
handleSort: (key: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useState as
|
|
1
|
+
"use strict";import{useState as d,useMemo as f}from"react";function K(u,m,l){const[t,i]=d(l),[a,c]=d("asc"),p=s=>{s===t?c(e=>e==="asc"?"desc":"asc"):(i(s),c("asc"))},D=(s,e)=>{i(s),c(e)},b=f(()=>[...u??[]].sort((s,e)=>{let r,o;const n=m[t];n?(r=n(s),o=n(e)):(r=s.metrics[t]??0,o=e.metrics[t]??0);const S=r<o?-1:r>o?1:0;return a==="asc"?S:-S}),[u,t,a,m]);return{sortKey:t,sortDir:a,handleSort:p,setSort:D,sortedData:b}}export{K as useBillableSort};
|
|
@@ -83,6 +83,11 @@ export interface ConversionOverTimeChartLegendBrand {
|
|
|
83
83
|
color: string;
|
|
84
84
|
dataKey?: string;
|
|
85
85
|
brandName?: string;
|
|
86
|
+
/**
|
|
87
|
+
* The brand's internal name. When provided, a Show Internal Brand Name toggle by the legend
|
|
88
|
+
* swaps `value` for it.
|
|
89
|
+
*/
|
|
90
|
+
internalName?: string;
|
|
86
91
|
}
|
|
87
92
|
export interface ConversionOverTimeChartProps {
|
|
88
93
|
data?: Array<Record<string, number | string>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useState as
|
|
1
|
+
"use strict";import{useState as T}from"react";import{Stack as $,Box as pe,ToggleButton as N,ToggleButtonGroup as Y}from"@mui/material";import{EmptyChartSection as G}from"../EmptyChartSection.mjs";import{LoadingChartSection as H}from"../LoadingChartSection.mjs";import{AreaChart as fe}from"../AreaChart/index.mjs";import{ConversionChartTooltip as he}from"./ConversionOverTimeChart.tooltip.mjs";import{trendSeries as ge}from"../trend.mjs";import{SeriesPercentageChartLegend as ve}from"../SeriesPercentageChartLegend/index.mjs";import{InternalBrandNameToggle as ye}from"../InternalBrandNameToggle/index.mjs";import{useStyle as be}from"../styles.mjs";import{formatExtendedDate as q,formatDateMMYY as xe}from"../../../utils/date.mjs";import{DEFAULT_TIMEZONE as ke}from"../../form/TimezoneInput/timezones.mjs";import{jsx as r,jsxs as w}from"react/jsx-runtime";const B="__trend_";function J(h,u,c){return h.map(i=>{const m=c==="sum"?u.reduce((o,p)=>o+(Number(i[p.dataKey])||0),0):Math.max(0,...u.map(o=>Number(i[o.dataKey])||0)),n={date:i.date};for(const o of u)n[o.dataKey]=m===0?0:(Number(i[o.dataKey])||0)/m;return n})}function Ce({brands:h,data:u,seriesConfig:c}){const i=new Map,m=h?new Set(h.map(n=>n._raw.brandUuid)):null;for(const n of u)if(!(m&&!m.has(n.brandUuid)))for(const o of n.interval??[]){const p=+new Date(o.date);let l=i.get(p);if(!l){l={date:p};for(const f of c)l[f.dataKey]=0;i.set(p,l)}for(const f of c)l[f.dataKey]=l[f.dataKey]+Number(o[f.dataKey]||0)}return{series:c,data:Array.from(i.values()).sort((n,o)=>n.date-o.date)}}function Ke({data:h,series:u,chartData:c,seriesConfig:i,stackMode:m="stack",isLoading:n,isFetching:o,isSuccess:p,filter:l,sx:f,legendBrand:s,showLegendUuid:Q=!0,views:L,defaultViewKey:R,extraToggles:z,toggleGroup:x,percentBasis:X="max",sortTooltipByValueDesc:A=!1}){var E;const P=be(),S=l.timezone??ke,k=L??[{key:"absolute",label:"Numbers",mode:"absolute"},{key:"percent",label:"Percentages",mode:"percent"}],[U,ee]=T(R??((E=k[0])==null?void 0:E.key)??"absolute"),[v,ae]=T(!1),[_,te]=T(!1),t=k.find(e=>e.key===U)??k[0],y=t?.mode??"absolute",M=t?.stackMode??m,re=t?.percentBasis??X,I=t?.chartData??c,oe=t?.seriesConfig??i,ne=t?.data??h,le=t?.series??u,d=I!==void 0?n?{series:[],data:[]}:Ce({brands:l.brands,data:I,seriesConfig:oe??[]}):{series:le??[],data:ne??[]},Z=!d.data.length||!p,j=!d.data.length&&n;if(!L){if(j)return r(H,{});if(Z)return r(G,{})}const ie=M==="none"&&y==="percent"?J(d.data,d.series,re):null,V=M==="stack"?y==="absolute"?"stack":"expand":"none",se=y==="absolute"?{tickFormatter:e=>Number(e).toLocaleString(),allowDecimals:!1}:{tickFormatter:e=>`${(e*100).toFixed(0)}%`,domain:[0,1]},O=y==="absolute"?e=>Number(e).toLocaleString():M==="stack"?(e,a,g)=>{const K=d.series.reduce((F,me)=>F+(Number(g.payload[me.dataKey])||0),0);return K===0?"0.0%":`${(Number(e)/K*100).toFixed(1)}%`}:e=>`${(Number(e)*100).toFixed(1)}%`,de=A?e=>-(Number(e?.value)||0):void 0,C=ie??d.data,D=y==="percent",W=V==="none"&&C.length>1,b=W?d.series.map(e=>{const a=ge(C,e.dataKey,{clampTo:D?[0,1]:void 0,interval:l.interval});return a?{serie:e,fit:a}:null}).filter(e=>e!==null):[],ue=b.map(({serie:e})=>`${B}${e.dataKey}`),ce=v&&b.length?C.map((e,a)=>{const g={...e};for(const{serie:K,fit:F}of b)g[`${B}${K.dataKey}`]=F.values[a];return g}):C;return w($,{children:[w(pe,{sx:{display:"flex",flexDirection:"column",gap:1,height:P.regularChartWrapper.height},children:[w($,{direction:"row",spacing:1,justifyContent:"flex-end",children:[W&&r(N,{value:"trend",selected:v,onChange:()=>ae(e=>!e),size:"small","aria-label":"Show trend line","aria-pressed":v,children:"Show Trend"}),z?.map(e=>r(N,{value:e.id,selected:e.selected,onChange:()=>e.onChange(!e.selected),size:"small","aria-label":e.ariaLabel??e.label,"aria-pressed":e.selected,children:e.label},e.id)),x&&r(Y,{value:x.value,exclusive:!0,onChange:(e,a)=>x.onChange(a),size:"small",children:x.options.map(e=>r(N,{value:e.key,"aria-label":e.ariaLabel??e.label,children:e.label},e.key))}),r(Y,{value:U,exclusive:!0,onChange:(e,a)=>{a!==null&&ee(a)},size:"small",children:k.map(e=>r(N,{value:e.key,children:e.label},e.key))})]}),j?r(H,{}):Z?r(G,{}):r(fe,{data:ce,series:d.series,trendLines:v?b.map(({serie:e})=>({dataKey:`${B}${e.dataKey}`,color:e.color,name:`${e.key} trend`})):void 0,stackMode:V,isAnimationActive:!0,xAxis:{dataKey:"date",type:"number",domain:["dataMin","dataMax"],tickFormatter:e=>xe(e,{timeZone:S,hour12:!1,hour:"numeric"}),allowDuplicatedCategory:!1},yAxis:se,tooltip:{formatter:O,itemSorter:de,labelFormatter:e=>q(e,{timeZone:S,hour12:!1}),content:r(he,{trendDataKeys:ue,trends:v?b.map(({serie:e,fit:a})=>({name:e.key,color:e.color,slope:D?a.slopePerInterval*100:a.slopePerInterval,stepMs:a.stepMs})):[],interval:l.interval,unit:D?"percent":"count",sortByValueDesc:A,valueFormatter:(e,a,g)=>O(e,a,g),labelFormatter:e=>q(e,{timeZone:S,hour12:!1})})},sx:{...P.regularChartWrapper,height:"unset",flex:1,minHeight:0,opacity:o?.4:1,...f}})]}),s&&w($,{spacing:1,children:[s.internalName!==void 0&&r(ye,{selected:_,onChange:te}),r(ve,{payload:[{uuid:s.uuid,value:_&&s.internalName?s.internalName:s.value,color:s.color,dataKey:s.dataKey??s.uuid,brandName:s.brandName}],showUuid:Q})]})]})}export{Ke as ConversionOverTimeChart,J as normalizePercentData};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
interface InternalBrandNameToggleProps {
|
|
3
|
+
selected: boolean;
|
|
4
|
+
onChange: (selected: boolean) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Sits by a chart's brand legend; swaps external brand names for internal ones. */
|
|
7
|
+
export declare function InternalBrandNameToggle({ selected, onChange, }: Readonly<InternalBrandNameToggleProps>): React.ReactNode;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{Stack as r,ToggleButton as t}from"@mui/material";import{jsx as a}from"react/jsx-runtime";function l({selected:e,onChange:n}){return a(r,{direction:"row",justifyContent:"flex-end",children:a(t,{value:"internal-brand-name",selected:e,onChange:()=>n(!e),size:"small","aria-label":"Show Internal Brand Name","aria-pressed":e,children:"Show Internal Brand Name"})})}export{l as InternalBrandNameToggle};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{Box as
|
|
1
|
+
"use strict";import{Box as d,Stack as c,Typography as t}from"@mui/material";import e from"@mui/material/Unstable_Grid2";import{AnimatePresence as l}from"framer-motion";import{MotionStack as p}from"../../animation/motions.mjs";import{CopyableUuid as s}from"../../CopyableUuid/index.mjs";import{jsx as r,jsxs as n}from"react/jsx-runtime";function m({entry:i,showUuid:a=!0}){return n(p,{component:"li",direction:"row",spacing:1,sx:{color:i.color},layout:"position",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},children:[r(d,{sx:{width:"3px",height:"100%",backgroundColor:i.color,borderRadius:3}}),n(c,{children:[r(t,{variant:"body1",children:i.value}),i.brandName&&r(t,{variant:"body2",children:i.brandName}),a&&i.uuid&&r(s,{uuid:i.uuid,label:"UUID",head:5,tail:0,variant:"text",mono:!1,typographyProps:{color:"inherit"}})]})]})}function u(i){const{payload:a}=i;return r(e,{container:!0,direction:"row",component:"ul",gap:2,sx:{mt:2,justifyContent:"flex-start",alignItem:"center",flexWrap:"wrap"},children:r(l,{children:a?.map(o=>r(e,{children:r(m,{entry:o,showUuid:i.showUuid})},`item-${o.uuid}-${o.dataKey}`))})})}export{u as SeriesPercentageChartLegend};
|
|
@@ -12,4 +12,4 @@ export declare function mergeChartData(seriesData: SeriesChartData[]): Array<Rec
|
|
|
12
12
|
/** Exported for testing. */
|
|
13
13
|
export declare const TOTAL_DATA_KEY = "__total__";
|
|
14
14
|
export declare function enrichWithTotal(entries: Array<Record<string, number>>, visibleBrandKeys: string[]): Array<Record<string, number>>;
|
|
15
|
-
export declare function SynchronizedMetricsChart({ subCharts, chartData, subChartConfig, colorMap, syncId, isLoading, isSuccess, isFetching, filter, sx, }: Readonly<SynchronizedMetricsChartProps>): React.ReactNode;
|
|
15
|
+
export declare function SynchronizedMetricsChart({ subCharts, chartData, subChartConfig, colorMap, syncId, isLoading, isSuccess, isFetching, filter, internalBrandNames, sx, }: Readonly<SynchronizedMetricsChartProps>): React.ReactNode;
|
|
@@ -21,3 +21,10 @@ export declare function mapSynchronizedSubCharts({ chartData, subChartConfig, br
|
|
|
21
21
|
colorMap: Map<string, string>;
|
|
22
22
|
isLoading: boolean;
|
|
23
23
|
}): [SubChartConfig, ...SubChartConfig[]];
|
|
24
|
+
/**
|
|
25
|
+
* Names each series by its brand's internal name instead of the external one. A keyword series
|
|
26
|
+
* (Text to Signup) stays named by its keyword and carries the brand in `brandName`; any other
|
|
27
|
+
* series is named by its brand. Brands without an internal name keep the external one, and the
|
|
28
|
+
* series order is kept so toggling names doesn't reshuffle the chart.
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyInternalBrandNames(subCharts: readonly [SubChartConfig, ...SubChartConfig[]], internalBrandNames: Map<string, string>): readonly [SubChartConfig, ...SubChartConfig[]];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{mapSeriesTimeSeriesData as
|
|
1
|
+
"use strict";import{mapSeriesTimeSeriesData as p}from"../SeriesChart/SeriesChart.map.mjs";function l({chartData:n,brands:o,numerator:i,denominator:s}){const d=new Set(o.map(r=>r._raw.brandUuid)),a=new Map;for(const r of n)if(d.has(r.brandUuid))for(const e of r.interval??[]){const u=+new Date(e.date),m=a.get(u)??{numerator:0,denominator:0};m.numerator+=Number(e[i])||0,m.denominator+=Number(e[s])||0,a.set(u,m)}const t={};for(const[r,e]of a)t[r]=e.denominator>0?Math.min(e.numerator/e.denominator*100,100):0;return t}function y({chartData:n,subChartConfig:o,brands:i,colorMap:s,isLoading:d}){if(d)return[{title:o[0].title,data:[]}];const a={brands:i,colorMap:s,data:n};return o.map(t=>{if(t.dataKey!=null)return{title:t.title,data:p({...a,keyValue:t.dataKey}),tooltipFormatter:t.tooltipFormatter,yAxisTickFormatter:t.yAxisTickFormatter,yAxisDomain:t.yAxisDomain,isPercentage:!1};const{numerator:r,denominator:e}=t.percentageOf,u=n.map(m=>({...m,interval:(m.interval??[]).map(c=>({...c,percentage:Number(c[e])>0?Math.min(Number(c[r])/Number(c[e])*100,100):0}))}));return{title:t.title,data:p({...a,data:u,keyValue:"percentage"}),tooltipFormatter:t.tooltipFormatter,yAxisTickFormatter:t.yAxisTickFormatter,yAxisDomain:t.yAxisDomain,isPercentage:!0,totalByDate:l({chartData:n,brands:i,numerator:r,denominator:e})}})}function b(n,o){const i=a=>{const t=a.brandUuid??a.uuid,r=o.get(t);if(!r)return a;const e=a.uuid!==t;return{...a,name:e?a.name:r,...a.brandName===void 0?{}:{brandName:r}}},[s,...d]=n.map(a=>({...a,data:a.data.map(i)}));return[s,...d]}export{b as applyInternalBrandNames,y as mapSynchronizedSubCharts,l as pooledPercentageByDate};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useState as
|
|
1
|
+
"use strict";import{useState as A,useMemo as b}from"react";import{Stack as x,ToggleButton as M,useTheme as R,Typography as X}from"@mui/material";import{ResponsiveContainer as q,LineChart as H,CartesianGrid as J,XAxis as Q,YAxis as V,Tooltip as $,Line as _}from"recharts";import{formatDateMMYY as ee}from"../../../utils/date.mjs";import{DEFAULT_TIMEZONE as te}from"../../form/TimezoneInput/timezones.mjs";import{EmptyChartSection as ae}from"../EmptyChartSection.mjs";import{LoadingChartSection as re}from"../LoadingChartSection.mjs";import{SeriesPercentageChartLegend as oe}from"../SeriesPercentageChartLegend/index.mjs";import{chartDefaultProps as ne,xAxisDefaultProps as ie,yAxisDefaultProps as se}from"../shared.mjs";import{mapSynchronizedSubCharts as le,applyInternalBrandNames as de}from"./SynchronizedMetricsChart.map.mjs";import{InternalBrandNameToggle as ce}from"../InternalBrandNameToggle/index.mjs";import{SynchronizedChartTooltip as me}from"./SynchronizedMetricsChart.tooltip.mjs";import{trendSeries as ue}from"../trend.mjs";import{jsx as t,jsxs as T}from"react/jsx-runtime";import pe from"../../../node_modules/d3-scale/src/symlog.mjs";const he="synchronized-metrics",ge=200,h="__total__",ye="Total",C="__trend__",fe="Trend";function Te(o){return!o.isPercentage||o.totalByDate?h:o.data.length===1?o.data[0].uuid:null}function j(o){const a=new Map;for(const i of o)for(const n of i.chartData){let d=a.get(n.date);d||(d={date:n.date},a.set(n.date,d)),d[i.uuid]=n.value}return Array.from(a.values()).sort((i,n)=>i.date-n.date)}const ve=h;function U(o,a){return a.length?o.map(i=>({...i,[h]:a.reduce((n,d)=>n+(Number(i[d])||0),0)})):o}function Se({title:o,mergedData:a,brands:i,timezone:n,syncId:d,isPercentage:c,showTotal:k,showTrend:g,trendTarget:u,interval:p,logScale:z,tooltipFormatter:w,yAxisTickFormatter:v,yAxisDomain:F}){const m=R(),P=z&&!c,S=k&&!c&&i.length>1,I=P?pe():void 0,s=b(()=>u?ue(a,u,{clampTo:c?[0,100]:void 0,interval:p}):null,[a,u,c,p]),L=b(()=>{if(!g||!s)return a;const r=a.length-1;return a.map((l,y)=>({...l,...y===0||y===r?{[C]:s.values[y]}:{}}))},[a,g,s]);return T(x,{children:[t(X,{variant:"h5",sx:{mb:.5,fontSize:"1.15rem"},children:o}),t(q,{width:"100%",height:ge,children:T(H,{data:L,syncId:d,margin:ne.margin,children:[t(J,{vertical:!1}),t(Q,{dataKey:"date",tickFormatter:r=>ee(r,{timeZone:n,hour12:!1,hour:"numeric"}),...ie}),t(V,{tickFormatter:v??(r=>Number(r).toLocaleString()),allowDecimals:!1,domain:F,scale:I,...se}),t($,{cursor:{stroke:m.palette.neutral.main,strokeWidth:1},wrapperStyle:{zIndex:m.zIndex.tooltip},content:t(me,{timezone:n,totalDataKey:h,trendDataKey:C,trendSlope:g?s?.slopePerInterval:void 0,trendStepMs:s?.stepMs,trendInterval:p,trendUnit:c?"percent":"count",valueFormatter:w??(r=>Number(r).toLocaleString())})}),i.map(r=>t(_,{dataKey:r.uuid,name:r.name,stroke:r.color,type:"monotone",strokeWidth:2,isAnimationActive:!1,dot:!1},r.uuid)),S&&t(_,{dataKey:h,name:ye,stroke:m.palette.text.primary,strokeWidth:2,strokeDasharray:"4 4",type:"monotone",isAnimationActive:!1,dot:!1},h),g&&s&&t(_,{dataKey:C,name:fe,connectNulls:!0,stroke:m.palette.secondary.main,strokeWidth:2,strokeDasharray:"7 5",type:"linear",isAnimationActive:!1,dot:!1,activeDot:!1,legendType:"none"},C)]})})]})}function xe({subCharts:o,chartData:a,subChartConfig:i,colorMap:n,syncId:d=he,isLoading:c,isSuccess:k,isFetching:g,filter:u,internalBrandNames:p,sx:z}){const w=u.timezone??te,[v,F]=A(!1),[m,P]=A(!1),[S,I]=A(!1),[s,L]=A(!1),r=a?le({chartData:a,subChartConfig:i,brands:u.brands,colorMap:n,isLoading:c}):o,l=s&&p?de(r,p):r,y=l.every(e=>e.data.length===0),W=b(()=>l.map(e=>{const f=j(e.data);if(e.isPercentage){const D=e.totalByDate;return D?f.map(Y=>({...Y,[h]:D[Y.date]??0})):f}const G=e.data.map(D=>D.uuid);return U(f,G)}),[l]),N=l.some(e=>!e.isPercentage),K=l.some(e=>!e.isPercentage&&e.data.length>1),B=l.map(e=>Te(e)),E=B.some(e=>e!==null),O=b(()=>l[0].data.map(e=>({uuid:e.brandUuid??e.uuid,value:e.name,color:e.color,dataKey:e.uuid,brandName:e.brandName})),[l]);if(y&&c)return t(re,{});if(y||!k)return t(ae,{});const Z=N||K||E;return T(x,{sx:{width:"100%",...z},children:[Z&&T(x,{direction:"row",spacing:1,justifyContent:"flex-end",sx:{mb:1},children:[K&&t(M,{value:"total",selected:v,onChange:()=>F(e=>!e),size:"small","aria-label":"Show Total line","aria-pressed":v,children:"Show Total"}),E&&t(M,{value:"trend",selected:m,onChange:()=>P(e=>!e),size:"small","aria-label":"Show trend line","aria-pressed":m,children:"Show Trend"}),N&&t(M,{value:"log",selected:S,onChange:()=>I(e=>!e),size:"small","aria-label":"Toggle logarithmic scale","aria-pressed":S,children:"Log Scale"})]}),T(x,{sx:{opacity:g?.4:1,gap:2},children:[l.map((e,f)=>t(Se,{title:e.title,mergedData:W[f],brands:e.data,timezone:w,syncId:d,isPercentage:e.isPercentage??!1,showTotal:v,showTrend:m,trendTarget:B[f],interval:u.interval,logScale:S,tooltipFormatter:e.tooltipFormatter,yAxisTickFormatter:e.yAxisTickFormatter,yAxisDomain:e.yAxisDomain},e.title)),T(x,{spacing:1,children:[p&&t(ce,{selected:s,onChange:L}),t(oe,{payload:O})]})]})]})}export{xe as SynchronizedMetricsChart,ve as TOTAL_DATA_KEY,U as enrichWithTotal,j as mergeChartData};
|
|
@@ -57,6 +57,11 @@ type SynchronizedMetricsChartBaseProps = {
|
|
|
57
57
|
*/
|
|
58
58
|
interval?: MetricsIntervalType;
|
|
59
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* Each brand's internal name, keyed by brand uuid. When provided, a Show Internal Brand Name
|
|
62
|
+
* toggle by the legend swaps the brands' external names for these in the legend and tooltip.
|
|
63
|
+
*/
|
|
64
|
+
internalBrandNames?: Map<string, string>;
|
|
60
65
|
sx?: SxProps;
|
|
61
66
|
};
|
|
62
67
|
export type SynchronizedMetricsChartProps = SynchronizedMetricsChartBaseProps & ({
|