fix: concurrency
This commit is contained in:
@@ -20,10 +20,7 @@ export const CreateItem = async (query: CreateItemQuery): Promise<ItemPriceRespo
|
||||
item_price: query.item_price
|
||||
})
|
||||
|
||||
const res = await axios.post(process.env.API_URL + `/item/create?${queryParams.toString()}`)
|
||||
if (res.data.Location) {
|
||||
window.location.href = res.data.Location
|
||||
}
|
||||
const res = await axios.post(process.env.NEXT_PUBLIC_API_URL + `/item/create?${queryParams.toString()}`, {}, {withCredentials: true})
|
||||
|
||||
return res.data
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {OrderTableQuery} from '../request/GetOrderTableRequest'
|
||||
axios.interceptors.response.use(response => {
|
||||
return response;
|
||||
}, async error => {
|
||||
if (error.response.status === 401) {
|
||||
if (error.response?.status === 401) {
|
||||
const resp = await axios.get(process.env.NEXT_PUBLIC_API_URL + "/auth/login", {withCredentials: true})
|
||||
window.location.href = resp.data.Location
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ export const GetCurrentUser = async (): Promise<UserResponse | undefined> => {
|
||||
console.log(process.env.NEXT_PUBLIC_API_URL + "/user/current")
|
||||
const res = await axios.get(process.env.NEXT_PUBLIC_API_URL + "/user/current", {
|
||||
maxRedirects: 0,
|
||||
withCredentials: true,
|
||||
validateStatus: (status) => {
|
||||
return status >= 200 && status < 400
|
||||
}});
|
||||
if(res.data.Location) {
|
||||
window.location.href = res.data.Location
|
||||
}
|
||||
return res.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'for client'
|
||||
import { useItemStore } from "../providers/ItemsProvider"
|
||||
import { useState } from "react"
|
||||
import useAsyncEffect from "use-async-effect"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'for client'
|
||||
import { useState } from "react"
|
||||
import styled from "styled-components"
|
||||
import { OrderItemTable } from "./OrderItemTable"
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,71 @@
|
||||
'use client'
|
||||
import { useState } from "react"
|
||||
import { ItemTableList } from "../components/ItemTableList"
|
||||
import useAsyncEffect from "use-async-effect"
|
||||
import { Mutex } from "async-mutex"
|
||||
import { useItemStore } from "../providers/ItemsProvider"
|
||||
import { useCurrentAuthenticatedUserStore } from "../providers"
|
||||
import { useShallow } from "zustand/shallow"
|
||||
|
||||
|
||||
const itemPageApiMutex = new Mutex()
|
||||
const Items = () => {
|
||||
|
||||
const [itemName, setItemName] = useState("")
|
||||
const [itemPrice, setItemPrice] = useState(0)
|
||||
const [inSeason, setInSeason] = useState(false)
|
||||
const [shouldSubmitDetails, setShouldSubmitDetails] = useState(false)
|
||||
|
||||
const itemStore = useItemStore((state) => state)
|
||||
|
||||
const authUserStore = useCurrentAuthenticatedUserStore(useShallow((state) => state))
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if(shouldSubmitDetails && authUserStore.Admin)
|
||||
{
|
||||
setShouldSubmitDetails(false)
|
||||
const release = await itemPageApiMutex.acquire()
|
||||
await itemStore.createItem(itemName, inSeason, itemPrice)
|
||||
|
||||
await release()
|
||||
}
|
||||
}, [shouldSubmitDetails])
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if(authUserStore.Id === -1) {
|
||||
const release = await itemPageApiMutex.acquire()
|
||||
await authUserStore.sync()
|
||||
await release()
|
||||
}
|
||||
}, [authUserStore])
|
||||
|
||||
|
||||
return (
|
||||
<ItemTableList />
|
||||
<>
|
||||
<ItemTableList />
|
||||
{authUserStore.Admin &&
|
||||
<>
|
||||
<h1 className="text-xl font-bold">Create Item</h1>
|
||||
<input placeholder="item name" onChange={(e) => {
|
||||
setItemName(e.currentTarget.value)
|
||||
}}/>
|
||||
<input placeholder="item price" onChange={(e) => {
|
||||
const int_value = parseInt(e.currentTarget.value)
|
||||
if(!Number.isNaN(int_value))
|
||||
setItemPrice(int_value)
|
||||
}}/>
|
||||
In Season
|
||||
<input className="ml-3" type="checkbox" onChange={(e) => {
|
||||
setInSeason(e.target.checked)
|
||||
}} />
|
||||
<br />
|
||||
<button onClick={() => {
|
||||
setShouldSubmitDetails(true)
|
||||
}} className="border p-1 mt-3 hover:bg-white hover:text-black">Create Item</button>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ export const useCurrentAuthenticatedUserStore = create<UserResponse & UserAction
|
||||
sync: async () => {
|
||||
const authUser = await GetCurrentUser()
|
||||
set((state) => ({
|
||||
...authUser,
|
||||
...state
|
||||
...state,
|
||||
...authUser
|
||||
}))
|
||||
return authUser
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user