-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create Zustand store for table column defs
- Loading branch information
1 parent
6d6ef1a
commit 714330e
Showing
4 changed files
with
119 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,3 +87,4 @@ probs | |
Customise | ||
popperjs | ||
tanstack | ||
upsert |
87 changes: 87 additions & 0 deletions
87
frontend/src/features/people/components/table/headers/AddPropertyHeader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { Popover, Transition } from '@headlessui/react'; | ||
import { SlimTextInput } from 'components/inputs'; | ||
import { usePeopleStore, PropertyDefinition } from 'features/people/stores/usePeopleStore'; | ||
import { Fragment, useCallback, useEffect, useRef, useState } from 'react'; | ||
import { MdAdd } from 'react-icons/md'; | ||
import { usePopper } from 'react-popper'; | ||
import _ from 'lodash'; | ||
import { nanoid } from 'nanoid'; | ||
|
||
const AddPropertyHeader = () => { | ||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null); | ||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null); | ||
const { styles, attributes } = usePopper(referenceElement, popperElement, { | ||
placement: 'bottom', | ||
}); | ||
|
||
const [id] = useState(() => nanoid()); // Initialize with a new GUID | ||
const [property, setProperty] = useState<Partial<Omit<PropertyDefinition, 'id'>>>({}); | ||
|
||
const debounce = useCallback( | ||
// Delay saving state until user activity stops | ||
_.debounce((definition: Partial<Omit<PropertyDefinition, 'id'>>) => { | ||
usePeopleStore.getState().upsertDefinition(id, definition); | ||
// API Calls go here | ||
const val = usePeopleStore.getState().propertyDefinitions; | ||
console.log(val); | ||
}, 750), // Delay (ms) | ||
[usePeopleStore.getState().propertyDefinitions], | ||
); | ||
|
||
const handleChange = useCallback( | ||
(event: React.ChangeEvent<HTMLInputElement>) => { | ||
const { name, value } = event.target; | ||
setProperty(prev => { | ||
const updatedProperty = { ...prev, [name]: value }; | ||
debounce(updatedProperty); | ||
return updatedProperty; | ||
}); | ||
}, | ||
[debounce], // Only recreate this function if debounceSave changes | ||
); | ||
|
||
return ( | ||
<Popover> | ||
{({ open }) => ( | ||
<> | ||
<Popover.Button ref={setReferenceElement} className="flex items-center p-2 outline-none"> | ||
<MdAdd className="text-center text-base text-grey-700" /> | ||
</Popover.Button> | ||
<Popover.Panel> | ||
<Transition | ||
show={open} | ||
as={Fragment} | ||
enter="transition ease-out duration-200" | ||
enterFrom="opacity-0 translate-y-1" | ||
enterTo="opacity-100 translate-y-0" | ||
leave="transition ease-in duration-150" | ||
leaveFrom="opacity-100 translate-y-0" | ||
leaveTo="opacity-0 translate-y-1"> | ||
<Popover.Panel | ||
static | ||
ref={setPopperElement} | ||
style={styles.popper} | ||
{...attributes.popper} | ||
className="w-64 overflow-hidden p-4 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5"> | ||
<SlimTextInput | ||
label="Display Name" | ||
placeholder="Property name" | ||
onChange={event => handleChange(event)} | ||
inputProps={{ name: 'header' }} | ||
/> | ||
<SlimTextInput | ||
label="Identifier" | ||
placeholder="property_name" | ||
onChange={event => handleChange(event)} | ||
inputProps={{ name: 'accessor' }} | ||
/> | ||
</Popover.Panel> | ||
</Transition> | ||
</Popover.Panel> | ||
</> | ||
)} | ||
</Popover> | ||
); | ||
}; | ||
|
||
export default AddPropertyHeader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { create } from 'zustand'; | ||
|
||
export interface PropertyDefinition { | ||
id: string; | ||
accessor?: string; | ||
header?: string; | ||
type?: string; | ||
} | ||
|
||
interface State { | ||
propertyDefinitions: Record<string, PropertyDefinition>; | ||
} | ||
|
||
//TODO: Maybe rename to upsertProperty ? | ||
interface Actions { | ||
upsertDefinition: (id: string, definition: Partial<Omit<PropertyDefinition, 'id'>>) => void; | ||
} | ||
|
||
export const usePeopleStore = create<State & Actions>(set => ({ | ||
propertyDefinitions: {}, | ||
upsertDefinition: (id, definition) => | ||
set(state => ({ | ||
propertyDefinitions: { | ||
...state.propertyDefinitions, | ||
[id]: { ...definition, id }, // Merge with the existing data | ||
}, | ||
})), | ||
})); |