Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 85 additions & 39 deletions apps/site/src/demos/dataTableDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ import {
TooltipSide,
} from '../../../../packages/blend/lib/components/Tooltip/types'

const isDateOnlyString = (value: string): boolean =>
/^\d{4}-\d{2}-\d{2}$/.test(value)

const parseDateOnlyLocal = (dateOnly: string): Date => {
const [y, m, d] = dateOnly.split('-').map((p) => Number(p))
return new Date(y, (m || 1) - 1, d || 1)
}

const parseDateLike = (value: unknown): Date | null => {
if (value instanceof Date) return isNaN(value.getTime()) ? null : value
if (typeof value !== 'string') return null
const trimmed = value.trim()
if (!trimmed) return null
const parsed = isDateOnlyString(trimmed)
? parseDateOnlyLocal(trimmed)
: new Date(trimmed)
return isNaN(parsed.getTime()) ? null : parsed
}

const SimpleDataTableExample = () => {
// Modal state for table demo
const [isTableModalOpen, setIsTableModalOpen] = useState(false)
Expand Down Expand Up @@ -454,7 +473,8 @@ const SimpleDataTableExample = () => {
isEditable: false,
renderCell: (value: unknown): React.ReactNode => {
const dateValue = value as DateColumnProps
const date = new Date(dateValue.date)
const date = parseDateLike(dateValue.date)
if (!date) return '-'
return (
<span>
{date.toLocaleDateString('en-US', {
Expand Down Expand Up @@ -517,7 +537,7 @@ const SimpleDataTableExample = () => {
<span>{selectedOption.label}</span>
</div>
) : (
// @ts-expect-error
// @ts-expect-error selectedValue can be non-renderable type in demo data
<span>{dropdownValue.selectedValue}</span>
)
},
Expand Down Expand Up @@ -1662,50 +1682,46 @@ const DataTableDemo = () => {

const statuses = ['Active', 'Inactive', 'Pending', 'Suspended']

const joinDates = [
'2014-08-01',
'2015-09-01',
'2016-03-01',
'2017-11-01',
'2018-07-01',
'2019-01-01',
'2020-04-01',
'2021-06-01',
'2022-10-01',
'2023-02-01',
'2020-05-01',
'2021-12-01',
'2022-03-01',
'2023-08-01',
'2019-11-01',
]

const formatJoinMonth = (dateString: string) => {
const parsed = parseDateLike(dateString)
if (!parsed) return '-'
return parsed.toLocaleDateString('en-US', {
month: 'long',
year: 'numeric',
})
}

return Array.from({ length: count }, (_, index) => {
const userName = names[index % names.length]
const userStatus = statuses[index % statuses.length]
const joinDate = joinDates[index % joinDates.length]

return {
id: index + 1,
name: {
label: userName,
sublabel: [
'August 2014',
'September 2015',
'March 2016',
'November 2017',
'July 2018',
'January 2019',
'April 2020',
'June 2021',
'October 2022',
'February 2023',
'May 2020',
'December 2021',
'March 2022',
'August 2023',
'November 2019',
][index % 15],
sublabel: formatJoinMonth(joinDate),
imageUrl: `https://randomuser.me/api/portraits/${index % 2 ? 'men' : 'women'}/${index % 70}.jpg`,
} as AvatarColumnProps,
joinDate: [
'August 2014',
'September 2015',
'March 2016',
'November 2017',
'July 2018',
'January 2019',
'April 2020',
'June 2021',
'October 2022',
'February 2023',
'May 2020',
'December 2021',
'March 2022',
'August 2023',
'November 2019',
][index % 15],
joinDate,
number: `${300 + index}`,
gateway: [
'Gateway A',
Expand Down Expand Up @@ -1912,6 +1928,25 @@ const DataTableDemo = () => {
minWidth: '150px',
maxWidth: '250px',
},
{
field: 'joinDate',
header: 'Join Date',
headerSubtext: 'Date user joined',
type: ColumnType.DATE,
isSortable: true,
isEditable: false,
renderCell: (value: unknown): React.ReactNode => {
const parsedDate = parseDateLike(String(value))
if (!parsedDate) return '-'
return parsedDate.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: '2-digit',
})
},
minWidth: '130px',
maxWidth: '170px',
},
{
field: 'role',
header: 'System Access Level and Authorization Status',
Expand Down Expand Up @@ -2517,7 +2552,12 @@ const DataTableDemo = () => {
`Last login: ${statusText === 'Active' ? '2 hours ago' : '1 week ago'}`,
`Profile updated: ${user.role === 'Admin' ? '1 day ago' : '3 days ago'}`,
`Password changed: ${user.gateway === 'Gateway A' ? '1 week ago' : '2 weeks ago'}`,
`Role assigned: ${user.joinDate}`,
`Role assigned: ${
parseDateLike(user.joinDate)?.toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
}) || '-'
}`,
]
return activities
}
Expand Down Expand Up @@ -2672,7 +2712,12 @@ const DataTableDemo = () => {
</div>
<div>
<strong>Member Since:</strong>{' '}
{userRow.joinDate}
{parseDateLike(
userRow.joinDate
)?.toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
}) || '-'}
</div>
</div>
</div>
Expand Down Expand Up @@ -2926,7 +2971,8 @@ const DataTableDemo = () => {
}

// Priority 3: Recently joined users - New members (2023+)
const joinYear = parseInt(userData.joinDate.split(' ')[1] || '2020')
const joinYear =
parseDateLike(userData.joinDate)?.getFullYear() ?? Number.NaN
if (joinYear >= 2023) {
return {
backgroundColor: '#f0fdf4', // Light green background
Expand Down
1 change: 1 addition & 0 deletions packages/blend/lib/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,7 @@ const DataTable = forwardRef(
currentPage={currentPage}
pageSize={pageSize}
totalRows={totalRows}
visibleRows={currentData.length}
isLoading={isLoading}
showSkeleton={showSkeleton}
hasData={currentData.length > 0}
Expand Down
24 changes: 24 additions & 0 deletions packages/blend/lib/components/DataTable/DataTablePagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type DataTablePaginationProps = {
currentPage: number
pageSize: number
totalRows: number
visibleRows?: number
pageSizeOptions: number[]
isLoading?: boolean
hasData?: boolean
Expand All @@ -27,6 +28,7 @@ export function DataTablePagination({
pageSize,
totalRows,
pageSizeOptions,
visibleRows = 0,
isLoading = false,
hasData = true,
isNarrowContainer = false,
Expand All @@ -39,6 +41,9 @@ export function DataTablePagination({
const PAGINATION_ITEM_HEIGHT = 33

const totalPages = Math.ceil(totalRows / pageSize)
const hasVisibleRows = hasData && visibleRows > 0
const rangeStart = hasVisibleRows ? (currentPage - 1) * pageSize + 1 : 0
const rangeEnd = hasVisibleRows ? rangeStart + visibleRows - 1 : 0

const getPageNumbers = () => {
const pages = []
Expand Down Expand Up @@ -254,6 +259,25 @@ export function DataTablePagination({
disabled={!hasData || isLoading}
/>
</Block>
<PrimitiveText
as="span"
fontSize={
tableToken.dataTable.table.footer.pagination.pageText
.fontSize
}
color={
tableToken.dataTable.table.footer.pagination.pageText
.color
}
style={{
whiteSpace: 'nowrap',
flexShrink: 0,
}}
>
{hasVisibleRows
? `${rangeStart}-${rangeEnd} of ${totalRows}`
: `0 of ${totalRows}`}
</PrimitiveText>
</Block>

<Block
Expand Down
64 changes: 44 additions & 20 deletions packages/blend/lib/components/DataTable/TableCell/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useResponsiveTokens } from '../../../hooks/useResponsiveTokens'
import { useResizeObserver } from '../../../hooks/useResizeObserver'
import Tooltip from '../../Tooltip/Tooltip'
import { TooltipSize } from '../../Tooltip/types'
import { parseDateLike } from '../utils'

const StyledTableCell = styled.td<{
width?: React.CSSProperties
Expand Down Expand Up @@ -59,13 +60,14 @@ const isEmptyValue = (value: unknown, columnType?: ColumnType): boolean => {
}

if (columnType === ColumnType.DATE) {
const dateData = value as DateColumnProps
const dateValue =
typeof value === 'object' && value !== null && 'date' in value
? (value as DateColumnProps).date
: value
if (
!dateData ||
!dateData.date ||
(typeof dateData.date === 'string' &&
dateData.date.trim() === '') ||
isNaN(new Date(dateData.date).getTime())
!dateValue ||
(typeof dateValue === 'string' && dateValue.trim() === '') ||
!parseDateLike(dateValue)
) {
return true
}
Expand Down Expand Up @@ -226,17 +228,31 @@ const TableCell = forwardRef<
attrs['data-numeric'] = String(valueToCheck || 0)
} else if (column.type === ColumnType.DATE) {
attrs['data-type'] = 'date'
const dateData = valueToCheck as DateColumnProps
if (dateData && dateData.date) {
const date = new Date(dateData.date)
if (!isNaN(date.getTime())) {
attrs['data-date'] = date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: '2-digit',
hour: dateData.showTime ? '2-digit' : undefined,
minute: dateData.showTime ? '2-digit' : undefined,
})
const dateValue =
typeof valueToCheck === 'object' &&
valueToCheck !== null &&
'date' in valueToCheck
? (valueToCheck as DateColumnProps).date
: valueToCheck
Comment thread
vinitkhandal717 marked this conversation as resolved.
const showTime =
typeof valueToCheck === 'object' &&
valueToCheck !== null &&
'showTime' in valueToCheck
? Boolean((valueToCheck as DateColumnProps).showTime)
: false
if (dateValue) {
const parsedDate = parseDateLike(dateValue)
if (parsedDate) {
attrs['data-date'] = parsedDate.toLocaleDateString(
'en-US',
{
year: 'numeric',
month: 'short',
day: '2-digit',
hour: showTime ? '2-digit' : undefined,
minute: showTime ? '2-digit' : undefined,
}
)
}
}
} else if (
Expand Down Expand Up @@ -412,7 +428,15 @@ const TableCell = forwardRef<
}

if (column.type === ColumnType.DATE && !isEditing) {
const dateData = displayValue as DateColumnProps
const dateData =
typeof displayValue === 'object' &&
displayValue !== null &&
'date' in displayValue
? (displayValue as DateColumnProps)
: ({
date: displayValue as Date | string,
showTime: false,
} as DateColumnProps)
Comment thread
vinitkhandal717 marked this conversation as resolved.

if (isEmptyValue(dateData, ColumnType.DATE)) {
return (
Expand All @@ -428,7 +452,7 @@ const TableCell = forwardRef<
)
}

const date = new Date(dateData.date)
const date = parseDateLike(dateData.date)
const showTime = dateData.showTime || false

const formatDate = (date: Date): string => {
Expand Down Expand Up @@ -459,7 +483,7 @@ const TableCell = forwardRef<
}}
>
<TruncatedTextWithTooltip
text={formatDate(date)}
text={date ? formatDate(date) : '-'}
style={{
fontSize:
FOUNDATION_THEME.font.size.body.sm.fontSize,
Expand Down
2 changes: 2 additions & 0 deletions packages/blend/lib/components/DataTable/TableFooter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const TableFooter = forwardRef<HTMLDivElement, TableFooterProps>(
currentPage,
pageSize,
totalRows,
visibleRows = 0,
isLoading,
showSkeleton,
onPageChange,
Expand Down Expand Up @@ -42,6 +43,7 @@ const TableFooter = forwardRef<HTMLDivElement, TableFooterProps>(
currentPage={currentPage}
pageSize={pageSize}
totalRows={totalRows}
visibleRows={visibleRows}
pageSizeOptions={
pagination.pageSizeOptions || [10, 20, 50, 100]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type TableFooterProps = {
currentPage: number
pageSize: number
totalRows: number
visibleRows?: number
isLoading?: boolean
showSkeleton?: boolean
hasData?: boolean
Expand Down
Loading
Loading