fix: application list item store not separated
This commit is contained in:
@@ -6,20 +6,20 @@ import {
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react"
|
||||
import { create } from "zustand"
|
||||
import { createStore, useStore } from "zustand"
|
||||
import { useShallow } from "zustand/react/shallow"
|
||||
import { Button } from "~/components/button"
|
||||
import { DEFAULT_NODE, type Entry } from "~/home/graph"
|
||||
import { useStore } from "./store"
|
||||
import { useRootStore } from "./store"
|
||||
|
||||
function ApplicationList() {
|
||||
const entries = useStore(useShallow((state) => state.entries))
|
||||
const entries = useRootStore(useShallow((state) => state.entries))
|
||||
return Object.values(entries).map((entry) => (
|
||||
<ApplicationListItem key={entry.name} entry={entry} />
|
||||
))
|
||||
}
|
||||
|
||||
interface ListItemStore {
|
||||
interface ListItemState {
|
||||
isAddingStage: boolean
|
||||
newStageValue: string
|
||||
|
||||
@@ -28,14 +28,15 @@ interface ListItemStore {
|
||||
addStage: (entryName: string) => void
|
||||
}
|
||||
|
||||
const useListItemStore = create<ListItemStore>()((set, get) => ({
|
||||
function createListItemStore() {
|
||||
return createStore<ListItemState>()((set, get) => ({
|
||||
isAddingStage: false,
|
||||
newStageValue: "",
|
||||
|
||||
setNewStageValue: (newStageValue: string) => set({ newStageValue }),
|
||||
setIsAddingStage: (isAddingStage: boolean) => set({ isAddingStage }),
|
||||
addStage: (entryName) => {
|
||||
const store = useStore.getState()
|
||||
const store = useRootStore.getState()
|
||||
let stage = get().newStageValue
|
||||
if (stage) {
|
||||
if (stage === DEFAULT_NODE.acceptedNode.key.toLowerCase()) {
|
||||
@@ -47,47 +48,80 @@ const useListItemStore = create<ListItemStore>()((set, get) => ({
|
||||
set({ isAddingStage: false, newStageValue: "" })
|
||||
}
|
||||
},
|
||||
}))
|
||||
}))
|
||||
}
|
||||
type ListItemStore = ReturnType<typeof createListItemStore>
|
||||
|
||||
const ListItemStoreContext = createContext<ListItemStore>(
|
||||
null as unknown as ListItemStore,
|
||||
)
|
||||
|
||||
function useListItemStore<T>(selector: (state: ListItemState) => T): T {
|
||||
const store = useContext(ListItemStoreContext)
|
||||
return useStore(store, selector)
|
||||
}
|
||||
|
||||
const EntryContext = createContext<Entry>(null as unknown as Entry)
|
||||
|
||||
const ApplicationListItem = memo(({ entry }: { entry: Entry }) => (
|
||||
const ApplicationListItem = memo(({ entry }: { entry: Entry }) => {
|
||||
const store = useRef<ListItemStore | null>(null)
|
||||
if (!store.current) {
|
||||
store.current = createListItemStore()
|
||||
}
|
||||
return (
|
||||
<ListItemStoreContext value={store.current}>
|
||||
<EntryContext value={entry}>
|
||||
<details className="w-full px-2 pb-2 -mx-2">
|
||||
<summary className="cursor-pointer">{entry.name}</summary>
|
||||
<ol className="pl-3 list-decimal list-inside text-sm">
|
||||
{entry.stages.map((step) => (
|
||||
<StageItem key={step} step={step} />
|
||||
<StageItem key={step} stage={step} />
|
||||
))}
|
||||
<NewStageInput />
|
||||
</ol>
|
||||
<ApplicationActions />
|
||||
</details>
|
||||
</EntryContext>
|
||||
))
|
||||
</ListItemStoreContext>
|
||||
)
|
||||
})
|
||||
|
||||
const StageItem = memo(({ step }: { step: string }) => {
|
||||
const entry = useContext(EntryContext)
|
||||
const deleteStageInEntry = useStore((state) => state.deleteStageInEntry)
|
||||
return (
|
||||
<li key={step} className="w-full group justify-between px-1">
|
||||
<div className="w-[90%] inline-flex flex-row items-center justify-between">
|
||||
{step}
|
||||
{step !== DEFAULT_NODE.applicationSubmittedNode.key ? (
|
||||
<Button
|
||||
variant="small"
|
||||
onClick={() => {
|
||||
deleteStageInEntry(step, entry.name)
|
||||
}}
|
||||
className="invisible group-hover:visible"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
const StageItem = memo(({ stage }: { stage: string }) => (
|
||||
<li key={stage} className="w-full group justify-between px-1">
|
||||
<div className="w-[90%] inline-flex flex-row flex-wrap items-center justify-between">
|
||||
{stage}
|
||||
{stage !== DEFAULT_NODE.applicationSubmittedNode.key ? (
|
||||
<StageItemActions stage={stage} />
|
||||
) : null}
|
||||
</div>
|
||||
</li>
|
||||
))
|
||||
|
||||
function StageItemActions({ stage }: { stage: string }) {
|
||||
const entry = useContext(EntryContext)
|
||||
const deleteStageInEntry = useRootStore((state) => state.deleteStageInEntry)
|
||||
|
||||
return (
|
||||
<div className="flex flex-row space-x-2 invisible group-hover:visible">
|
||||
<Button
|
||||
variant="small"
|
||||
onClick={() => {
|
||||
deleteStageInEntry(stage, entry.name)
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
<Button
|
||||
variant="small"
|
||||
onClick={() => {
|
||||
deleteStageInEntry(stage, entry.name)
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function NewStageInput() {
|
||||
const isAddingStage = useListItemStore((state) => state.isAddingStage)
|
||||
@@ -142,8 +176,8 @@ function ApplicationActions() {
|
||||
const DefaultActions = memo(() => {
|
||||
const entry = useContext(EntryContext)
|
||||
const setIsAddingStage = useListItemStore((state) => state.setIsAddingStage)
|
||||
const addStageToEntry = useStore((state) => state.addStageInEntry)
|
||||
const deleteEntry = useStore((state) => state.deleteEntry)
|
||||
const addStageToEntry = useRootStore((state) => state.addStageInEntry)
|
||||
const deleteEntry = useRootStore((state) => state.deleteEntry)
|
||||
|
||||
const isApplicationFinalized =
|
||||
entry.stages.at(-1) === DEFAULT_NODE.acceptedNode.key ||
|
||||
|
@@ -2,7 +2,7 @@ import { create } from "zustand/index"
|
||||
import { immer } from "zustand/middleware/immer"
|
||||
import { DEFAULT_NODE, type Entry, type Node } from "~/home/graph"
|
||||
|
||||
interface Store {
|
||||
interface RootStore {
|
||||
nodes: Record<string, Node>
|
||||
starts: Node["key"][]
|
||||
entries: Record<string, Entry>
|
||||
@@ -10,11 +10,12 @@ interface Store {
|
||||
addEntry: (name: string) => void
|
||||
hasEntry: (name: string) => boolean
|
||||
addStageInEntry: (stage: string, entryName: string) => void
|
||||
editStageInEntry: (i: number, stage: string, entryName: string) => void
|
||||
deleteStageInEntry: (stage: string, entryName: string) => void
|
||||
deleteEntry: (entryName: string) => void
|
||||
}
|
||||
|
||||
const useStore = create<Store>()(
|
||||
const useRootStore = create<RootStore>()(
|
||||
immer((set, get) => ({
|
||||
isAddingEntry: false,
|
||||
nodes: {
|
||||
@@ -72,6 +73,17 @@ const useStore = create<Store>()(
|
||||
}
|
||||
}),
|
||||
|
||||
editStageInEntry: (i, stage, entryName) =>
|
||||
set((state) => {
|
||||
const entry = state.entries[entryName]
|
||||
if (entry && stage) {
|
||||
if (i >= entry.stages.length) {
|
||||
return
|
||||
}
|
||||
entry.stages[i] = stage
|
||||
}
|
||||
}),
|
||||
|
||||
deleteStageInEntry: (stage, entryName) =>
|
||||
set((state) => {
|
||||
if (stage === DEFAULT_NODE.applicationSubmittedNode.key) {
|
||||
@@ -119,4 +131,4 @@ const useStore = create<Store>()(
|
||||
})),
|
||||
)
|
||||
|
||||
export { useStore }
|
||||
export { useRootStore }
|
||||
|
@@ -4,7 +4,7 @@ import Chart from "react-google-charts"
|
||||
import { Button } from "~/components/button"
|
||||
import { ApplicationList } from "~/home/application-list"
|
||||
import type { Node } from "~/home/graph"
|
||||
import { useStore } from "~/home/store"
|
||||
import { useRootStore } from "~/home/store"
|
||||
import { Queue } from "~/queue"
|
||||
import { useUiMode } from "~/use-ui-mode"
|
||||
|
||||
@@ -35,8 +35,8 @@ export default function Home() {
|
||||
}
|
||||
|
||||
function FlufferChart() {
|
||||
const nodes = useStore((state) => state.nodes)
|
||||
const starts = useStore((state) => state.starts)
|
||||
const nodes = useRootStore((state) => state.nodes)
|
||||
const starts = useRootStore((state) => state.starts)
|
||||
const uiMode = useUiMode()
|
||||
|
||||
const data = useMemo(() => {
|
||||
@@ -86,8 +86,8 @@ function FlufferChart() {
|
||||
|
||||
function AddApplicationForm() {
|
||||
const [isAddingEntry, setIsAddingEntry] = useState(false)
|
||||
const addEntry = useStore((state) => state.addEntry)
|
||||
const hasEntry = useStore((state) => state.hasEntry)
|
||||
const addEntry = useRootStore((state) => state.addEntry)
|
||||
const hasEntry = useRootStore((state) => state.hasEntry)
|
||||
const inputRef = useRef<HTMLInputElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
|
Reference in New Issue
Block a user