Skip to content

Commit 4664438

Browse files
committed
Aggregation for comment bubbles, comment tool does not work
1 parent 63021d8 commit 4664438

File tree

7 files changed

+273
-115
lines changed

7 files changed

+273
-115
lines changed

apps/react/tables/libraries/AgGrid/marketing-spend-demo/components/document/day-view-table-component.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React, { useEffect, useMemo, useCallback } from 'react';
3+
import React, { useEffect, useMemo, useCallback, useState } from 'react';
44
import { VeltComments, useVeltClient } from '@veltdev/react';
55
import { AgGridReact } from 'ag-grid-react';
66
import { AllCommunityModule, ModuleRegistry } from 'ag-grid-community';
@@ -11,7 +11,7 @@ ModuleRegistry.registerModules([AllCommunityModule]);
1111

1212
// Import modularized components and utilities
1313
import { customDarkTheme } from './constants';
14-
import { dateComparator } from './utils';
14+
import { dateComparator, aggregateDataByWeek, aggregateDataByMonth } from './utils';
1515
import { createCustomHeaderComponent } from './grid-components/CustomHeaderComponent';
1616
import { RowNumberRenderer } from './grid-components/RowNumberRenderer';
1717
import { createVeltCellRenderer } from './grid-components/VeltCellRenderer';
@@ -20,9 +20,11 @@ import { ViewToggle } from './ui-components/ViewToggle';
2020
import { Toolbar } from './ui-components/Toolbar';
2121
import { styles } from './styles';
2222
import { useTableState } from './hooks/useTableState';
23+
import { ViewType } from './types';
2324

2425
export const TableComponent: React.FC = () => {
2526
const { client } = useVeltClient();
27+
const [viewType, setViewType] = useState<ViewType>('day');
2628
const {
2729
selectedCell,
2830
setSelectedCell,
@@ -39,6 +41,18 @@ export const TableComponent: React.FC = () => {
3941
setAlignment,
4042
} = useTableState();
4143

44+
// Generate display data based on view type
45+
const displayData = useMemo(() => {
46+
switch (viewType) {
47+
case 'week':
48+
return aggregateDataByWeek(rowData);
49+
case 'month':
50+
return aggregateDataByMonth(rowData);
51+
default:
52+
return rowData;
53+
}
54+
}, [viewType, rowData]);
55+
4256
// Initialize Velt
4357
useEffect(() => {
4458
if (client) {
@@ -91,10 +105,10 @@ export const TableComponent: React.FC = () => {
91105
return createCustomHeaderComponent(localSortState, setLocalSortState);
92106
}, [localSortState]);
93107

94-
// Cell Renderer with Velt formatting
108+
// Cell Renderer with Velt formatting and context
95109
const veltCellRenderer = useMemo(() => {
96-
return createVeltCellRenderer(cellFormatting);
97-
}, [cellFormatting]);
110+
return createVeltCellRenderer(cellFormatting, viewType);
111+
}, [cellFormatting, viewType]);
98112

99113
// Column Definitions
100114
const columnDefs = useMemo(() => [
@@ -258,7 +272,10 @@ export const TableComponent: React.FC = () => {
258272
/>
259273

260274
<div style={styles.tableContainer}>
261-
<ViewToggle />
275+
<ViewToggle
276+
currentView={viewType}
277+
onViewChange={setViewType}
278+
/>
262279

263280
<Toolbar
264281
toggleFormatting={toggleFormatting}
@@ -271,7 +288,7 @@ export const TableComponent: React.FC = () => {
271288
<div style={styles.gridWrapper}>
272289
<AgGridReact
273290
theme={customDarkTheme}
274-
rowData={rowData}
291+
rowData={displayData}
275292
columnDefs={columnDefs}
276293
defaultColDef={defaultColDef}
277294
onGridReady={onGridReady}
Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,21 @@
11
import React from 'react';
2-
import { CellFormatting } from '../types';
3-
import { getCellFormattingKey } from '../utils';
4-
5-
export const createVeltCellRenderer = (cellFormatting: Record<string, CellFormatting>) => (props: any) => {
6-
const cellId = `cell-${props.data.id}-${props.colDef.field}`;
2+
import { VeltCommentTool, VeltCommentBubble } from '@veltdev/react';
3+
import { CellFormatting, ViewType } from '../types';
4+
import { getCellFormattingKey, generateCommentContext } from '../utils';
5+
6+
export const createVeltCellRenderer = (
7+
cellFormatting: Record<string, CellFormatting>,
8+
viewType: ViewType
9+
) => (props: any) => {
710
const cellKey = getCellFormattingKey(props.data.id, props.colDef.field);
811
const formatting = cellFormatting[cellKey] || {};
912

10-
// Set ID on parent AG Grid cell element and add comment tool
11-
React.useEffect(() => {
12-
if (props.eGridCell) {
13-
if (props.eGridCell.id !== cellId) {
14-
props.eGridCell.id = cellId;
15-
}
16-
17-
// Check if comment tool already exists
18-
let commentTool = props.eGridCell.querySelector('velt-comment-tool');
19-
if (!commentTool) {
20-
// Create and append comment tool directly to cell
21-
commentTool = document.createElement('velt-comment-tool');
22-
commentTool.setAttribute('target-comment-element-id', cellId);
23-
commentTool.style.cssText = 'position: absolute; right: 4px; top: 50%; transform: translateY(-50%); z-index: 1;';
24-
25-
// Append to cell (outside ag-cell-wrapper)
26-
props.eGridCell.appendChild(commentTool);
27-
} else {
28-
// Update target-comment-element-id if it changed
29-
if (commentTool.getAttribute('target-comment-element-id') !== cellId) {
30-
commentTool.setAttribute('target-comment-element-id', cellId);
31-
}
32-
}
33-
}
34-
35-
return () => {
36-
// Cleanup: remove comment tool when cell is destroyed
37-
if (props.eGridCell) {
38-
const commentTool = props.eGridCell.querySelector('velt-comment-tool');
39-
if (commentTool) {
40-
commentTool.remove();
41-
}
42-
}
43-
};
44-
}, [cellId, props.eGridCell]);
13+
// Generate comment context - this is the primary identifier for aggregation
14+
const commentContext = generateCommentContext(
15+
props.data,
16+
props.colDef.field,
17+
viewType
18+
);
4519

4620
const textStyle: React.CSSProperties = {
4721
fontWeight: formatting.bold ? 'bold' : 'normal',
@@ -60,11 +34,21 @@ export const createVeltCellRenderer = (cellFormatting: Record<string, CellFormat
6034
height: '100%',
6135
padding: '4px 12px 4px 12px',
6236
textAlign: formatting.align || 'left',
37+
position: 'relative',
6338
};
6439

6540
return (
6641
<div style={containerStyle}>
6742
<span style={textStyle}>{props.value}</span>
43+
{/* Removed targetCommentElementId - rely on context for aggregation */}
44+
<VeltCommentTool
45+
context={commentContext}
46+
contextOptions={{ partialMatch: true }}
47+
/>
48+
<VeltCommentBubble
49+
context={commentContext}
50+
contextOptions={{ partialMatch: true }}
51+
/>
6852
</div>
6953
);
7054
};

apps/react/tables/libraries/AgGrid/marketing-spend-demo/components/document/types.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ export interface TableData {
55
linkedin: string;
66
facebook: string;
77
instagram: string;
8+
dateMetadata?: {
9+
day: number; // 1-31
10+
month: number; // 1-12
11+
year: number; // 2025
12+
week: number; // ISO week number (1-53)
13+
};
814
}
915

1016
export interface CellFormatting {
@@ -24,3 +30,13 @@ export interface SortState {
2430
colId: string;
2531
sort: 'asc' | 'desc';
2632
}
33+
34+
export type ViewType = 'day' | 'week' | 'month';
35+
36+
export interface CommentContext {
37+
channel: string; // "linkedin" | "facebook" | "instagram" | "x"
38+
day?: number; // Only in day view
39+
week?: number; // In day & week views
40+
month: number;
41+
year: number;
42+
}

apps/react/tables/libraries/AgGrid/marketing-spend-demo/components/document/ui-components/ViewToggle.tsx

Lines changed: 43 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
import React from 'react';
2+
import { ViewType } from '../types';
3+
4+
interface ViewToggleProps {
5+
currentView: ViewType;
6+
onViewChange: (view: ViewType) => void;
7+
}
8+
9+
export const ViewToggle: React.FC<ViewToggleProps> = ({ currentView, onViewChange }) => {
10+
const getButtonStyle = (isActive: boolean) => ({
11+
backgroundColor: isActive ? 'rgba(255, 255, 255, 0.08)' : 'transparent',
12+
border: 'none',
13+
borderRadius: '8px',
14+
padding: '4px 8px',
15+
cursor: 'pointer',
16+
display: 'flex',
17+
alignItems: 'center',
18+
justifyContent: 'center',
19+
});
20+
21+
const getTextStyle = (isActive: boolean) => ({
22+
fontFamily: 'Urbanist, sans-serif',
23+
fontSize: '13px',
24+
fontWeight: 400,
25+
lineHeight: '16px',
26+
color: isActive ? '#ffffff' : 'rgba(255, 255, 255, 0.52)',
27+
whiteSpace: 'pre' as const,
28+
letterSpacing: '0.13px',
29+
});
230

3-
export const ViewToggle: React.FC = () => {
431
return (
532
<div style={{
633
position: 'absolute',
@@ -12,65 +39,23 @@ export const ViewToggle: React.FC = () => {
1239
gap: '4px',
1340
zIndex: 10,
1441
}}>
15-
<button style={{
16-
backgroundColor: 'rgba(255, 255, 255, 0.08)',
17-
border: 'none',
18-
borderRadius: '8px',
19-
padding: '4px 8px',
20-
cursor: 'pointer',
21-
display: 'flex',
22-
alignItems: 'center',
23-
justifyContent: 'center',
24-
}}>
25-
<span style={{
26-
fontFamily: 'Urbanist, sans-serif',
27-
fontSize: '13px',
28-
fontWeight: 400,
29-
lineHeight: '16px',
30-
color: '#ffffff',
31-
whiteSpace: 'pre',
32-
letterSpacing: '0.13px',
33-
}}>Day View</span>
42+
<button
43+
style={getButtonStyle(currentView === 'day')}
44+
onClick={() => onViewChange('day')}
45+
>
46+
<span style={getTextStyle(currentView === 'day')}>Day View</span>
3447
</button>
35-
<button style={{
36-
backgroundColor: 'transparent',
37-
border: 'none',
38-
borderRadius: '8px',
39-
padding: '4px 8px',
40-
cursor: 'pointer',
41-
display: 'flex',
42-
alignItems: 'center',
43-
justifyContent: 'center',
44-
}}>
45-
<span style={{
46-
fontFamily: 'Urbanist, sans-serif',
47-
fontSize: '13px',
48-
fontWeight: 400,
49-
lineHeight: '16px',
50-
color: 'rgba(255, 255, 255, 0.52)',
51-
whiteSpace: 'pre',
52-
letterSpacing: '0.13px',
53-
}}>Weekly View</span>
48+
<button
49+
style={getButtonStyle(currentView === 'week')}
50+
onClick={() => onViewChange('week')}
51+
>
52+
<span style={getTextStyle(currentView === 'week')}>Weekly View</span>
5453
</button>
55-
<button style={{
56-
backgroundColor: 'transparent',
57-
border: 'none',
58-
borderRadius: '8px',
59-
padding: '4px 8px',
60-
cursor: 'pointer',
61-
display: 'flex',
62-
alignItems: 'center',
63-
justifyContent: 'center',
64-
}}>
65-
<span style={{
66-
fontFamily: 'Urbanist, sans-serif',
67-
fontSize: '13px',
68-
fontWeight: 400,
69-
lineHeight: '16px',
70-
color: 'rgba(255, 255, 255, 0.52)',
71-
whiteSpace: 'pre',
72-
letterSpacing: '0.13px',
73-
}}>Monthly View</span>
54+
<button
55+
style={getButtonStyle(currentView === 'month')}
56+
onClick={() => onViewChange('month')}
57+
>
58+
<span style={getTextStyle(currentView === 'month')}>Monthly View</span>
7459
</button>
7560
</div>
7661
);

0 commit comments

Comments
 (0)