mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-05-06 19:39:36 +00:00
Generated by Spark: Load more of UI from JSON declarations and break up large components into atomic and create hooks as needed
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { useState, useCallback } from 'react'
|
||||
|
||||
export interface ConfirmDialogOptions {
|
||||
title: string
|
||||
description: string
|
||||
confirmText?: string
|
||||
cancelText?: string
|
||||
variant?: 'default' | 'destructive'
|
||||
}
|
||||
|
||||
export interface ConfirmDialogState {
|
||||
isOpen: boolean
|
||||
options: ConfirmDialogOptions | null
|
||||
resolve: ((value: boolean) => void) | null
|
||||
}
|
||||
|
||||
export function useConfirmDialog() {
|
||||
const [state, setState] = useState<ConfirmDialogState>({
|
||||
isOpen: false,
|
||||
options: null,
|
||||
resolve: null,
|
||||
})
|
||||
|
||||
const confirm = useCallback((options: ConfirmDialogOptions): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
setState({
|
||||
isOpen: true,
|
||||
options,
|
||||
resolve,
|
||||
})
|
||||
})
|
||||
}, [])
|
||||
|
||||
const handleConfirm = useCallback(() => {
|
||||
if (state.resolve) {
|
||||
state.resolve(true)
|
||||
}
|
||||
setState({ isOpen: false, options: null, resolve: null })
|
||||
}, [state.resolve])
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
if (state.resolve) {
|
||||
state.resolve(false)
|
||||
}
|
||||
setState({ isOpen: false, options: null, resolve: null })
|
||||
}, [state.resolve])
|
||||
|
||||
return {
|
||||
isOpen: state.isOpen,
|
||||
options: state.options,
|
||||
confirm,
|
||||
handleConfirm,
|
||||
handleCancel,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { useState, useCallback } from 'react'
|
||||
|
||||
export interface FormFieldConfig<T = any> {
|
||||
name: string
|
||||
defaultValue: T
|
||||
validate?: (value: T) => string | null
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export interface FormState<T extends Record<string, any>> {
|
||||
values: T
|
||||
errors: Partial<Record<keyof T, string>>
|
||||
touched: Partial<Record<keyof T, boolean>>
|
||||
isValid: boolean
|
||||
isDirty: boolean
|
||||
}
|
||||
|
||||
export function useFormState<T extends Record<string, any>>(
|
||||
fields: FormFieldConfig[],
|
||||
initialValues?: Partial<T>
|
||||
) {
|
||||
const defaultValues = fields.reduce((acc, field) => {
|
||||
acc[field.name] = initialValues?.[field.name] ?? field.defaultValue
|
||||
return acc
|
||||
}, {} as T)
|
||||
|
||||
const [state, setState] = useState<FormState<T>>({
|
||||
values: defaultValues,
|
||||
errors: {},
|
||||
touched: {},
|
||||
isValid: true,
|
||||
isDirty: false,
|
||||
})
|
||||
|
||||
const validateField = useCallback(
|
||||
(name: keyof T, value: any): string | null => {
|
||||
const field = fields.find((f) => f.name === name)
|
||||
if (!field) return null
|
||||
|
||||
if (field.required && !value) {
|
||||
return 'This field is required'
|
||||
}
|
||||
|
||||
if (field.validate) {
|
||||
return field.validate(value)
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
[fields]
|
||||
)
|
||||
|
||||
const validateAll = useCallback((): boolean => {
|
||||
const newErrors: Partial<Record<keyof T, string>> = {}
|
||||
let isValid = true
|
||||
|
||||
fields.forEach((field) => {
|
||||
const error = validateField(field.name as keyof T, state.values[field.name])
|
||||
if (error) {
|
||||
newErrors[field.name as keyof T] = error
|
||||
isValid = false
|
||||
}
|
||||
})
|
||||
|
||||
setState((prev) => ({ ...prev, errors: newErrors, isValid }))
|
||||
return isValid
|
||||
}, [fields, state.values, validateField])
|
||||
|
||||
const setValue = useCallback(
|
||||
(name: keyof T, value: any) => {
|
||||
setState((prev) => {
|
||||
const newValues = { ...prev.values, [name]: value }
|
||||
const error = validateField(name, value)
|
||||
const newErrors = { ...prev.errors }
|
||||
|
||||
if (error) {
|
||||
newErrors[name] = error
|
||||
} else {
|
||||
delete newErrors[name]
|
||||
}
|
||||
|
||||
return {
|
||||
...prev,
|
||||
values: newValues,
|
||||
errors: newErrors,
|
||||
isDirty: true,
|
||||
isValid: Object.keys(newErrors).length === 0,
|
||||
}
|
||||
})
|
||||
},
|
||||
[validateField]
|
||||
)
|
||||
|
||||
const setTouched = useCallback((name: keyof T) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
touched: { ...prev.touched, [name]: true },
|
||||
}))
|
||||
}, [])
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setState({
|
||||
values: defaultValues,
|
||||
errors: {},
|
||||
touched: {},
|
||||
isValid: true,
|
||||
isDirty: false,
|
||||
})
|
||||
}, [defaultValues])
|
||||
|
||||
const setValues = useCallback((newValues: Partial<T>) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
values: { ...prev.values, ...newValues },
|
||||
isDirty: true,
|
||||
}))
|
||||
}, [])
|
||||
|
||||
return {
|
||||
values: state.values,
|
||||
errors: state.errors,
|
||||
touched: state.touched,
|
||||
isValid: state.isValid,
|
||||
isDirty: state.isDirty,
|
||||
setValue,
|
||||
setTouched,
|
||||
setValues,
|
||||
reset,
|
||||
validateAll,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import { useState, useCallback } from 'react'
|
||||
|
||||
export interface ListOperationsOptions<T> {
|
||||
initialItems?: T[]
|
||||
getId?: (item: T) => string | number
|
||||
onItemsChange?: (items: T[]) => void
|
||||
}
|
||||
|
||||
export function useListOperations<T>({
|
||||
initialItems = [],
|
||||
getId = (item: any) => item.id,
|
||||
onItemsChange,
|
||||
}: ListOperationsOptions<T> = {}) {
|
||||
const [items, setItemsState] = useState<T[]>(initialItems)
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string | number>>(new Set())
|
||||
|
||||
const setItems = useCallback(
|
||||
(newItems: T[] | ((prev: T[]) => T[])) => {
|
||||
setItemsState((prev) => {
|
||||
const updated = typeof newItems === 'function' ? newItems(prev) : newItems
|
||||
onItemsChange?.(updated)
|
||||
return updated
|
||||
})
|
||||
},
|
||||
[onItemsChange]
|
||||
)
|
||||
|
||||
const addItem = useCallback(
|
||||
(item: T, position?: number) => {
|
||||
setItems((prev) => {
|
||||
if (position !== undefined && position >= 0 && position <= prev.length) {
|
||||
const newItems = [...prev]
|
||||
newItems.splice(position, 0, item)
|
||||
return newItems
|
||||
}
|
||||
return [...prev, item]
|
||||
})
|
||||
},
|
||||
[setItems]
|
||||
)
|
||||
|
||||
const updateItem = useCallback(
|
||||
(id: string | number, updates: Partial<T> | ((item: T) => T)) => {
|
||||
setItems((prev) =>
|
||||
prev.map((item) => {
|
||||
if (getId(item) === id) {
|
||||
return typeof updates === 'function' ? updates(item) : { ...item, ...updates }
|
||||
}
|
||||
return item
|
||||
})
|
||||
)
|
||||
},
|
||||
[getId, setItems]
|
||||
)
|
||||
|
||||
const removeItem = useCallback(
|
||||
(id: string | number) => {
|
||||
setItems((prev) => prev.filter((item) => getId(item) !== id))
|
||||
setSelectedIds((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
newSet.delete(id)
|
||||
return newSet
|
||||
})
|
||||
},
|
||||
[getId, setItems]
|
||||
)
|
||||
|
||||
const removeItems = useCallback(
|
||||
(ids: (string | number)[]) => {
|
||||
const idSet = new Set(ids)
|
||||
setItems((prev) => prev.filter((item) => !idSet.has(getId(item))))
|
||||
setSelectedIds((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
ids.forEach((id) => newSet.delete(id))
|
||||
return newSet
|
||||
})
|
||||
},
|
||||
[getId, setItems]
|
||||
)
|
||||
|
||||
const moveItem = useCallback(
|
||||
(fromIndex: number, toIndex: number) => {
|
||||
setItems((prev) => {
|
||||
if (
|
||||
fromIndex < 0 ||
|
||||
fromIndex >= prev.length ||
|
||||
toIndex < 0 ||
|
||||
toIndex >= prev.length
|
||||
) {
|
||||
return prev
|
||||
}
|
||||
const newItems = [...prev]
|
||||
const [movedItem] = newItems.splice(fromIndex, 1)
|
||||
newItems.splice(toIndex, 0, movedItem)
|
||||
return newItems
|
||||
})
|
||||
},
|
||||
[setItems]
|
||||
)
|
||||
|
||||
const toggleSelection = useCallback((id: string | number) => {
|
||||
setSelectedIds((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
if (newSet.has(id)) {
|
||||
newSet.delete(id)
|
||||
} else {
|
||||
newSet.add(id)
|
||||
}
|
||||
return newSet
|
||||
})
|
||||
}, [])
|
||||
|
||||
const selectAll = useCallback(() => {
|
||||
setSelectedIds(new Set(items.map(getId)))
|
||||
}, [items, getId])
|
||||
|
||||
const clearSelection = useCallback(() => {
|
||||
setSelectedIds(new Set())
|
||||
}, [])
|
||||
|
||||
const removeSelected = useCallback(() => {
|
||||
removeItems(Array.from(selectedIds))
|
||||
}, [selectedIds, removeItems])
|
||||
|
||||
const findById = useCallback(
|
||||
(id: string | number) => {
|
||||
return items.find((item) => getId(item) === id)
|
||||
},
|
||||
[items, getId]
|
||||
)
|
||||
|
||||
const clear = useCallback(() => {
|
||||
setItems([])
|
||||
setSelectedIds(new Set())
|
||||
}, [setItems])
|
||||
|
||||
return {
|
||||
items,
|
||||
selectedIds: Array.from(selectedIds),
|
||||
selectedCount: selectedIds.size,
|
||||
isEmpty: items.length === 0,
|
||||
setItems,
|
||||
addItem,
|
||||
updateItem,
|
||||
removeItem,
|
||||
removeItems,
|
||||
moveItem,
|
||||
toggleSelection,
|
||||
selectAll,
|
||||
clearSelection,
|
||||
removeSelected,
|
||||
findById,
|
||||
clear,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user