fix: concurrency

This commit is contained in:
2025-11-19 12:26:37 -07:00
parent e1396e2d24
commit 80e57eaa2b
19 changed files with 175 additions and 60 deletions

View File

@@ -5,6 +5,8 @@ import { ItemHistoryTable } from "./ItemHistoryTable"
import useAsyncEffect from "use-async-effect"
import { useItemStore } from "../providers/ItemsProvider"
import { Mutex } from "async-mutex"
import { useCurrentAuthenticatedUserStore } from "../providers"
import { useShallow } from "zustand/shallow"
type ItemTableListRowProps = {
item: ItemPriceResponse
@@ -56,15 +58,25 @@ export const ItemTableListRow = ({item}: ItemTableListRowProps) => {
const [shouldPushNewItemPrice, setShouldPushNewItemPrice] = useState<boolean>(false)
const authUserStore = useCurrentAuthenticatedUserStore(useShallow((state) => state))
useAsyncEffect(async () => {
if(shouldPushNewItemPrice)
if(shouldPushNewItemPrice && authUserStore.Admin)
{
const release = await itemTableListRowMutex.acquire()
setShouldPushNewItemPrice(false)
await itemStore.setItemPrice(item.ItemId, newItemPrice)
await release()
}
}, [shouldPushNewItemPrice])
}, [shouldPushNewItemPrice, authUserStore])
useAsyncEffect(async () => {
if (authUserStore.Id === -1) {
const release = await itemTableListRowMutex.acquire()
await authUserStore.sync()
await release()
}
}, [authUserStore])
return (
<li>
@@ -79,7 +91,7 @@ export const ItemTableListRow = ({item}: ItemTableListRowProps) => {
price: {Math.trunc(item.ItemPrice * 100) / 100}
</ItemFieldContainer>
</ItemOverviewContainer>
{shouldShowDetails && (
{shouldShowDetails && authUserStore.Admin && (
<>
<ItemDetailsContainer>
<h1 className="text-xl">Set Item Price</h1>

View File

@@ -1,11 +1,29 @@
'use client'
import Link from "next/link"
import { useCurrentAuthenticatedUserStore } from "../providers"
import useAsyncEffect from "use-async-effect"
import { Mutex } from "async-mutex"
import { useShallow } from "zustand/shallow"
const navBarMutex = new Mutex()
export const NavBar = () => {
const authUserStore = useCurrentAuthenticatedUserStore(useShallow((state) => state))
useAsyncEffect(async () => {
if(authUserStore.Id === -1) {
const release = await navBarMutex.acquire()
await authUserStore.sync()
await release()
}
}, [authUserStore])
return (
<nav>
<div className="flex items-center justify-center">
<Link className=" pl-7 pr-7 pt-3 pb-3 hover:bg-purple-950" href="/orders/0/0">Orders</Link>
<Link className=" pl-7 pr-7 pt-3 pb-3 hover:bg-purple-950" href="/users/0">Users</Link>
{authUserStore.Admin && (<Link className=" pl-7 pr-7 pt-3 pb-3 hover:bg-purple-950" href="/users/0">Users</Link>)}
<Link className=" pl-7 pr-7 pt-3 pb-3 hover:bg-purple-950" href="/items">Items</Link>
</div>
</nav>

View File

@@ -1,3 +1,4 @@
'for client'
import { useItemStore } from "../providers/ItemsProvider"
import { useState } from "react"
import useAsyncEffect from "use-async-effect"

View File

@@ -2,9 +2,9 @@
import { useOrderStore } from "../providers/OrderProvider"
import { useShallow } from "zustand/shallow"
import useAsyncEffect from "use-async-effect"
import { OrderTableRow } from "./OrderTableRow"
import { Mutex } from "async-mutex"
import styled from "styled-components"
import { OrderTableRow } from "./OrderTableRow"
type OrderTableProps = {
page: number,

View File

@@ -1,3 +1,4 @@
'for client'
import { useState } from "react"
import styled from "styled-components"
import { OrderItemTable } from "./OrderItemTable"

View File

@@ -4,6 +4,8 @@ import { useUserStore } from "../providers/UsersProvider"
import useAsyncEffect from "use-async-effect"
import styled from "styled-components"
import { useRef, useState } from "react"
import { useCurrentAuthenticatedUserStore } from "../providers"
import { Mutex } from "async-mutex"
type UserTableProps = {
page: number
@@ -35,6 +37,8 @@ const UserTableRow = styled.tr`
`
const userTableMutex = new Mutex()
export const UserTable = ({page}: UserTableProps) => {
const userStore = useUserStore(useShallow((state) => ({
@@ -43,47 +47,59 @@ export const UserTable = ({page}: UserTableProps) => {
console.log(page)
const [callLock, setCallLock] = useState<boolean>(false)
const authUserStore = useCurrentAuthenticatedUserStore(useShallow((state) => state))
console.log(authUserStore)
const callLockRef = useRef(callLock)
useAsyncEffect(async () => {
if(!callLockRef.current) {
if(!callLockRef.current && authUserStore.Admin) {
callLockRef.current = true
setCallLock(true)
await userStore.sync(page)
callLockRef.current = false
setCallLock(false)
}
}, [page])
}, [page, authUserStore.Id, authUserStore.Name])
useAsyncEffect(async () => {
if(authUserStore.Id === -1) {
const release = await userTableMutex.acquire()
await authUserStore.sync()
console.log(authUserStore)
await release()
}
}, [authUserStore.Id])
console.log(userStore.tableUsers)
return (
<UserTableStyle>
<UserTableHead>
<UserTH>id</UserTH>
<UserTH>name</UserTH>
<UserTH>position</UserTH>
<UserTH>active</UserTH>
<UserTH>admin</UserTH>
</UserTableHead>
<UserTableBody>
{userStore.tableUsers.map((u) => (
<UserTableRow key={u.Id}>
<UserTableItem>{u.Id}</UserTableItem>
<UserTableItem>{u.Name}</UserTableItem>
<UserTableItem>{u.JobPosition}</UserTableItem>
<UserTableItem><input type="checkbox" defaultValue={u.Active ? "yes" : "no"} onChange={async (e) => {
if(u.Active)
await userStore.deactivateUser(u.Id)
else
await userStore.activateUser(u.Id)
}}/></UserTableItem>
<UserTableItem><input type="checkbox" value={u.Admin ? "yes" : "no"} onChange={async (e) => {
if(u.Admin)
await userStore.demoteUser(u.Id)
else
await userStore.promoteUser(u.Id)
}}/></UserTableItem>
</UserTableRow>))}
</UserTableBody>
</UserTableStyle>
return authUserStore.Admin && (
<UserTableStyle>
<UserTableHead>
<tr>
<UserTH>id</UserTH>
<UserTH>name</UserTH>
<UserTH>position</UserTH>
<UserTH>active</UserTH>
<UserTH>admin</UserTH>
</tr>
</UserTableHead>
<UserTableBody>
{userStore.tableUsers.map((u) => (
<UserTableRow key={u.Id}>
<UserTableItem>{u.Id}</UserTableItem>
<UserTableItem>{u.Name}</UserTableItem>
<UserTableItem>{u.JobPosition}</UserTableItem>
<UserTableItem><input type="checkbox" onChange={async (e) => {
if(u.Active)
await userStore.deactivateUser(u.Id)
else
await userStore.activateUser(u.Id)
}} checked={u.Active}/></UserTableItem>
<UserTableItem><input type="checkbox" onChange={async (e) => {
if(u.Admin)
await userStore.demoteUser(u.Id)
else
await userStore.promoteUser(u.Id)
}} checked={u.Admin}/></UserTableItem>
</UserTableRow>))}
</UserTableBody>
</UserTableStyle>
)
}