import { useState, useCallback, useMemo, useEffect, useRef } from "react" import { HttpTypes } from "@medusajs/types" type ViewConfiguration = HttpTypes.AdminViewConfigurationResponse["view_configuration"] interface ColumnState { visibility: Record order: string[] } interface UseColumnStateReturn { visibleColumns: Record columnOrder: string[] columnState: ColumnState currentColumns: { visible: string[] order: string[] } setVisibleColumns: (visibility: Record) => void setColumnOrder: (order: string[]) => void handleColumnVisibilityChange: (visibility: Record) => void handleViewChange: ( view: ViewConfiguration | null, apiColumns: HttpTypes.AdminColumn[] ) => void initializeColumns: (apiColumns: HttpTypes.AdminColumn[]) => void } export function useColumnState( apiColumns: HttpTypes.AdminColumn[] | undefined, activeView?: ViewConfiguration | null ): UseColumnStateReturn { // Initialize state lazily to avoid unnecessary re-renders const [visibleColumns, setVisibleColumns] = useState>( () => { if (apiColumns?.length && activeView?.configuration) { // If there's an active view, initialize with its configuration const visibility: Record = {} apiColumns.forEach((column) => { visibility[column.field] = activeView.configuration.visible_columns?.includes(column.field) || false }) return visibility } else if (apiColumns?.length) { return getInitialColumnVisibility(apiColumns) } return {} } ) const [columnOrder, setColumnOrder] = useState(() => { if (activeView?.configuration?.column_order) { // If there's an active view, use its column order return activeView.configuration.column_order } else if (apiColumns?.length) { return getInitialColumnOrder(apiColumns) } return [] }) const columnState = useMemo( () => ({ visibility: visibleColumns, order: columnOrder, }), [visibleColumns, columnOrder] ) const currentColumns = useMemo(() => { const visible = Object.entries(visibleColumns) .filter(([_, isVisible]) => isVisible) .map(([field]) => field) return { visible, order: columnOrder, } }, [visibleColumns, columnOrder]) const handleColumnVisibilityChange = useCallback( (visibility: Record) => { setVisibleColumns(visibility) }, [] ) const handleViewChange = useCallback( (view: ViewConfiguration | null, apiColumns: HttpTypes.AdminColumn[]) => { if (view?.configuration) { // Apply view configuration const newVisibility: Record = {} apiColumns.forEach((column) => { newVisibility[column.field] = view.configuration.visible_columns?.includes(column.field) || false }) setVisibleColumns(newVisibility) setColumnOrder(view.configuration.column_order || []) } else { // Reset to default visibility when no view is selected setVisibleColumns(getInitialColumnVisibility(apiColumns)) setColumnOrder(getInitialColumnOrder(apiColumns)) } }, [] ) const initializeColumns = useCallback( (apiColumns: HttpTypes.AdminColumn[]) => { // Only initialize if we don't already have column state if (Object.keys(visibleColumns).length === 0) { setVisibleColumns(getInitialColumnVisibility(apiColumns)) } if (columnOrder.length === 0) { setColumnOrder(getInitialColumnOrder(apiColumns)) } }, [] ) // Track previous active view to detect changes const prevActiveViewRef = useRef() // Sync local state when active view changes useEffect(() => { if (apiColumns?.length) { // Check if this is a different view or an update to the same view const viewChanged = prevActiveViewRef.current?.id !== activeView?.id const viewUpdated = activeView && prevActiveViewRef.current?.id === activeView.id && prevActiveViewRef.current.updated_at !== activeView.updated_at if (viewChanged || viewUpdated) { if (activeView?.configuration) { // Apply the active view's configuration const newVisibility: Record = {} apiColumns.forEach((column) => { newVisibility[column.field] = activeView.configuration?.visible_columns?.includes( column.field ) || false }) setVisibleColumns(newVisibility) setColumnOrder(activeView.configuration?.column_order || []) } else { // No active view - reset to defaults setVisibleColumns(getInitialColumnVisibility(apiColumns)) setColumnOrder(getInitialColumnOrder(apiColumns)) } } } prevActiveViewRef.current = activeView }, [activeView, apiColumns]) return { visibleColumns, columnOrder, columnState, currentColumns, setVisibleColumns, setColumnOrder, handleColumnVisibilityChange, handleViewChange, initializeColumns, } } // Utility functions const DEFAULT_COLUMN_ORDER = 500 /** * Gets the initial column visibility state from API columns */ function getInitialColumnVisibility( apiColumns: HttpTypes.AdminColumn[] ): Record { if (!apiColumns || apiColumns.length === 0) { return {} } const visibility: Record = {} apiColumns.forEach((column) => { visibility[column.field] = column.default_visible ?? true }) return visibility } /** * Gets the initial column order from API columns */ function getInitialColumnOrder(apiColumns: HttpTypes.AdminColumn[]): string[] { if (!apiColumns || apiColumns.length === 0) { return [] } const sortedColumns = [...apiColumns].sort((a, b) => { const orderA = a.default_order ?? DEFAULT_COLUMN_ORDER const orderB = b.default_order ?? DEFAULT_COLUMN_ORDER return orderA - orderB }) return sortedColumns.map((col) => col.field) }