Skip to content

Instantly share code, notes, and snippets.

@fullstackjedi
Created May 11, 2024 18:01
Show Gist options
  • Save fullstackjedi/ebca6401696d0453908ae95da2325028 to your computer and use it in GitHub Desktop.
Save fullstackjedi/ebca6401696d0453908ae95da2325028 to your computer and use it in GitHub Desktop.
import { PresenceFacepile, PresenceObserver } from '@cord-sdk/react'
import { useMemo } from 'react'
import { useWorkspaceState } from '@pulse-modules/workspace/state/use-workspace-state'
import { TEntity, TEntityRecord, TEntityView, TEntityViewField } from '@pulse-types/entities'
import {
CountryCellEditor,
CurrencyCellEditor,
DateCellEditor,
DomainCellEditor,
EmailCellEditor,
GridBoolean,
GridCheckbox,
GridColumnHeader,
GridCurrency,
GridDate,
GridDomain,
GridEmail,
GridLink,
GridPhone,
GridRecord,
GridSelect,
GridStarRating,
GridStatus,
GridText,
GridUsers,
ICellRendererParams,
IRowNode,
NumberCellEditor,
SelectCellEditor,
StatusCellEditor,
SuppressKeyboardEventParams,
TextCellEditor,
TimestampCellEditor,
UrlCellEditor,
UsersCellEditor
} from '@pulse-ui/primitives/data-grid'
import { Flex } from '@pulse-ui/primitives/layout'
import { GridPrimaryColumnRenderer } from '../components/entity-grid/primary-column-renderer'
// import { Text } from '@pulse-ui/primitives/text'
import { useUpdateEntityRecordValues } from '../mutations/use-update-entity-record-values'
const attributesThatDontNeedEditors = ['checkbox', 'rating', 'boolean']
export const useGridColumns = (entity: TEntity, view: TEntityView) => {
const activeWorkspace = useWorkspaceState((state) => state.activeWorkspace)
const updateRecordMutation = useUpdateEntityRecordValues()
const onUpdateCell = ({
colId,
rowNode,
data,
field,
value,
defaultValue
}: {
colId: string
rowNode: IRowNode
data: TEntityRecord
field: TEntityViewField
value: any
defaultValue: any
}) => {
updateRecordMutation.mutateAsync({
entityId: entity.id,
recordId: data.id || '',
body: {
attributeId: field.attributeId,
value
},
onErrorCallback: () => rowNode.setDataValue(colId, defaultValue)
})
}
const columns = useMemo(() => {
if (view) {
const { fields } = view
const tableData = fields.map((field) => {
// Cell editor
let cellEditor
if (field.attribute.type === 'text') {
cellEditor = TextCellEditor
} else if (field.attribute.type === 'number') {
cellEditor = NumberCellEditor
} else if (field.attribute.type === 'currency') {
cellEditor = CurrencyCellEditor
} else if (field.attribute.type === 'date') {
cellEditor = DateCellEditor
} else if (field.attribute.type === 'timestamp') {
cellEditor = TimestampCellEditor
} else if (field.attribute.type === 'status') {
cellEditor = StatusCellEditor
} else if (field.attribute.type === 'select') {
cellEditor = SelectCellEditor
} else if (field.attribute.type === 'domain') {
cellEditor = DomainCellEditor
} else if (field.attribute.type === 'email') {
cellEditor = EmailCellEditor
} else if (field.attribute.type === 'url') {
cellEditor = UrlCellEditor
} else if (field.attribute.type === 'user') {
cellEditor = UsersCellEditor
} else if (field.attribute.type === 'country') {
cellEditor = CountryCellEditor
}
return {
field: `values.${field.attribute.key}`,
pinned:
field.attribute.isPrimary ||
field.isPinned ||
entity.primaryAttributeId === field.attributeId,
filter: true,
hide: !field.isVisible,
resizable: true,
minWidth: field.attribute.isPrimary ? 250 : undefined,
maxWidth: 350,
// valueGetter: 'node.id',
cellRenderer: (params: ICellRendererParams<TEntityRecord>) => {
const value = params.value
const data = params.data
const rowId = params.data?.id
const colId = params.column?.getColId()
let content = <></>
if (!data || !value || !rowId || !colId || !activeWorkspace) {
return null
}
if (field.attribute.isPrimary) {
content = (
<GridPrimaryColumnRenderer
entity={entity}
attribute={field.attribute}
node={params.node}
record={data}
/>
)
} else {
switch (field.attribute.type) {
case 'checkbox':
content = (
<GridCheckbox
isEditable={field.attribute.isEditable}
defaultValue={value}
onChange={(checked) => {
if (params.data) {
onUpdateCell({
colId: params.column?.getColId() || '',
rowNode: params.node,
data: params.data,
field,
value: checked,
defaultValue: !checked
})
}
}}
/>
)
break
case 'currency':
content = <GridCurrency value={value} />
break
case 'date':
content = <GridDate date={value} />
break
case 'rating':
content = (
<GridStarRating
isEditable={field.attribute.isEditable}
defaultValue={value}
onChange={(val) => {
if (params.data) {
onUpdateCell({
colId: params.column?.getColId() || '',
rowNode: params.node,
data: params.data,
field,
value: val,
defaultValue: value
})
}
}}
/>
)
break
case 'status':
content = <GridStatus data={value} />
break
case 'select':
content = <GridSelect data={value} />
break
case 'user':
content = <GridUsers userIds={value} />
break
case 'record':
content = <GridRecord records={value} />
break
case 'domain':
content = <GridDomain domain={value} />
break
case 'email':
content = <GridEmail value={value} />
break
case 'phone':
content = <GridPhone value={value} />
break
case 'url':
content = <GridLink url={value} />
break
case 'boolean':
content = (
<GridBoolean
isEditable={field.attribute.isEditable}
defaultValue={value}
onChange={(checked) => {
if (params.data) {
onUpdateCell({
colId: params.column?.getColId() || '',
rowNode: params.node,
data: params.data,
field,
value: checked,
defaultValue: !checked
})
}
}}
/>
)
break
// case 'text', 'number', 'timestamp'
default:
content = <GridText value={value} />
}
}
// return content
return (
<CellWithPresence
groupId={activeWorkspace.workspaceId}
location={{
entityId: entity.id,
viewId: view.id,
rowId,
colId
}}
>
{content}
</CellWithPresence>
)
},
headerComponent: GridColumnHeader,
headerComponentParams: {
fieldData: field,
showSelectAllCheckbox: field.attribute.isPrimary
},
editable:
field.attribute.isEditable &&
!attributesThatDontNeedEditors.includes(field.attribute.type),
cellEditor,
cellEditorParams: {
fieldData: field,
onUpdateCallBack: onUpdateCell
},
cellEditorPopup: field.attribute.type === 'text',
suppressKeyboardEvent: (params: SuppressKeyboardEventParams) => {
if (false) return true // if isLoading
const key = params.event.key
const gridShouldDoNothing = params.editing && key === 'Enter' && params.event.shiftKey
return gridShouldDoNothing
},
// Custom
fieldData: field
}
})
return tableData
} else {
return []
}
}, [view])
return columns
}
export const CellWithPresence = ({
groupId,
location,
children
}: {
groupId: string
location: Record<string, string>
children: React.ReactNode
}) => {
return (
<PresenceObserver groupId={groupId} location={location}>
<Flex gap="2" h="100%" w="100%" align="center" justify="space-between">
{children}
<PresenceFacepile location={location} excludeViewer={true} maxUsers={3} />
</Flex>
</PresenceObserver>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment