fix: concurrency
This commit is contained in:
Binary file not shown.
@@ -3,7 +3,6 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -44,7 +43,7 @@ func TokenIsNotExpired(access_token string) bool {
|
|||||||
func GetUserProfile(context *gin.Context) {
|
func GetUserProfile(context *gin.Context) {
|
||||||
|
|
||||||
session := sessions.Default(context)
|
session := sessions.Default(context)
|
||||||
access_token := session.Get("access_token")
|
/* access_token := session.Get("access_token")
|
||||||
user_profile_client := http.Client{}
|
user_profile_client := http.Client{}
|
||||||
|
|
||||||
user_profile_url, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + os.Getenv("AUTH0_USER_INFO_ENDPOINT"))
|
user_profile_url, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + os.Getenv("AUTH0_USER_INFO_ENDPOINT"))
|
||||||
@@ -71,10 +70,15 @@ func GetUserProfile(context *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer user_profile_response.Body.Close()
|
defer user_profile_response.Body.Close()
|
||||||
user_profile_bytes, _ := io.ReadAll(user_profile_response.Body)
|
user_profile_bytes, _ := io.ReadAll(user_profile_response.Body) */
|
||||||
|
|
||||||
var user_profile dto.UserProfileResponse
|
var user_profile dto.UserProfileResponse
|
||||||
json.Unmarshal(user_profile_bytes, &user_profile)
|
profile_session := session.Get("profile").(map[string]interface{})
|
||||||
|
user_profile.Sub = profile_session["sub"].(string)
|
||||||
|
user_profile.Email = profile_session["email"].(string)
|
||||||
|
user_profile.Verified = profile_session["email_verified"].(bool)
|
||||||
|
user_profile.PictureUrl = profile_session["picture"].(string)
|
||||||
|
user_profile.Nickname = profile_session["nickname"].(string)
|
||||||
|
user_profile.Updated_at = profile_session["updated_at"].(string)
|
||||||
context.Set("user_profile", user_profile)
|
context.Set("user_profile", user_profile)
|
||||||
context.Next()
|
context.Next()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ func GetCurrentAuthenticatedUser(pool *pgxpool.Pool) gin.HandlerFunc {
|
|||||||
|
|
||||||
user_profile, _ := ctx.Get("user_profile")
|
user_profile, _ := ctx.Get("user_profile")
|
||||||
|
|
||||||
|
log.Printf("%s", user_profile.(dto.UserProfileResponse).Sub)
|
||||||
|
|
||||||
sub_id := user_profile.(dto.UserProfileResponse).Sub
|
sub_id := user_profile.(dto.UserProfileResponse).Sub
|
||||||
|
|
||||||
var user dto.UserResponse
|
var user dto.UserResponse
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package dto
|
|||||||
// User response for exposing to the front-end
|
// User response for exposing to the front-end
|
||||||
// :3
|
// :3
|
||||||
type UserResponse struct {
|
type UserResponse struct {
|
||||||
Id int `json: "id"`
|
Id int
|
||||||
Name string `json: "name"`
|
Name string
|
||||||
JobPosition string `json: "job_position"`
|
JobPosition string
|
||||||
Active bool `json: "active"`
|
Active bool
|
||||||
Admin bool `json: "admin"`
|
Admin bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ func main() {
|
|||||||
router.GET("/item/history", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.GetItemHistory(pool))
|
router.GET("/item/history", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.GetItemHistory(pool))
|
||||||
router.POST("/position/create", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.CreatePosition(pool))
|
router.POST("/position/create", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.CreatePosition(pool))
|
||||||
router.POST("/item/create", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.CreateItem(pool))
|
router.POST("/item/create", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.CreateItem(pool))
|
||||||
|
router.OPTIONS("/item/create", corsmiddleware.CORSMiddleware)
|
||||||
router.POST("/order/create", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.CreateOrder(pool))
|
router.POST("/order/create", corsmiddleware.CORSMiddleware, user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.CreateOrder(pool))
|
||||||
router.OPTIONS("/order/create", corsmiddleware.CORSMiddleware)
|
router.OPTIONS("/order/create", corsmiddleware.CORSMiddleware)
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ FROM
|
|||||||
ordr_user
|
ordr_user
|
||||||
LEFT JOIN ordr_position
|
LEFT JOIN ordr_position
|
||||||
ON job_position = ordr_position.id
|
ON job_position = ordr_position.id
|
||||||
AND ordr_user.sub_id = $1;
|
WHERE
|
||||||
|
ordr_user.sub_id = $1;
|
||||||
`
|
`
|
||||||
|
|
||||||
const USER_SET_POSITION string = `
|
const USER_SET_POSITION string = `
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ export const CreateItem = async (query: CreateItemQuery): Promise<ItemPriceRespo
|
|||||||
item_price: query.item_price
|
item_price: query.item_price
|
||||||
})
|
})
|
||||||
|
|
||||||
const res = await axios.post(process.env.API_URL + `/item/create?${queryParams.toString()}`)
|
const res = await axios.post(process.env.NEXT_PUBLIC_API_URL + `/item/create?${queryParams.toString()}`, {}, {withCredentials: true})
|
||||||
if (res.data.Location) {
|
|
||||||
window.location.href = res.data.Location
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {OrderTableQuery} from '../request/GetOrderTableRequest'
|
|||||||
axios.interceptors.response.use(response => {
|
axios.interceptors.response.use(response => {
|
||||||
return response;
|
return response;
|
||||||
}, async error => {
|
}, 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})
|
const resp = await axios.get(process.env.NEXT_PUBLIC_API_URL + "/auth/login", {withCredentials: true})
|
||||||
window.location.href = resp.data.Location
|
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")
|
console.log(process.env.NEXT_PUBLIC_API_URL + "/user/current")
|
||||||
const res = await axios.get(process.env.NEXT_PUBLIC_API_URL + "/user/current", {
|
const res = await axios.get(process.env.NEXT_PUBLIC_API_URL + "/user/current", {
|
||||||
maxRedirects: 0,
|
maxRedirects: 0,
|
||||||
|
withCredentials: true,
|
||||||
validateStatus: (status) => {
|
validateStatus: (status) => {
|
||||||
return status >= 200 && status < 400
|
return status >= 200 && status < 400
|
||||||
}});
|
}});
|
||||||
if(res.data.Location) {
|
|
||||||
window.location.href = res.data.Location
|
|
||||||
}
|
|
||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { ItemHistoryTable } from "./ItemHistoryTable"
|
|||||||
import useAsyncEffect from "use-async-effect"
|
import useAsyncEffect from "use-async-effect"
|
||||||
import { useItemStore } from "../providers/ItemsProvider"
|
import { useItemStore } from "../providers/ItemsProvider"
|
||||||
import { Mutex } from "async-mutex"
|
import { Mutex } from "async-mutex"
|
||||||
|
import { useCurrentAuthenticatedUserStore } from "../providers"
|
||||||
|
import { useShallow } from "zustand/shallow"
|
||||||
|
|
||||||
type ItemTableListRowProps = {
|
type ItemTableListRowProps = {
|
||||||
item: ItemPriceResponse
|
item: ItemPriceResponse
|
||||||
@@ -56,15 +58,25 @@ export const ItemTableListRow = ({item}: ItemTableListRowProps) => {
|
|||||||
|
|
||||||
const [shouldPushNewItemPrice, setShouldPushNewItemPrice] = useState<boolean>(false)
|
const [shouldPushNewItemPrice, setShouldPushNewItemPrice] = useState<boolean>(false)
|
||||||
|
|
||||||
|
const authUserStore = useCurrentAuthenticatedUserStore(useShallow((state) => state))
|
||||||
|
|
||||||
useAsyncEffect(async () => {
|
useAsyncEffect(async () => {
|
||||||
if(shouldPushNewItemPrice)
|
if(shouldPushNewItemPrice && authUserStore.Admin)
|
||||||
{
|
{
|
||||||
const release = await itemTableListRowMutex.acquire()
|
const release = await itemTableListRowMutex.acquire()
|
||||||
setShouldPushNewItemPrice(false)
|
setShouldPushNewItemPrice(false)
|
||||||
await itemStore.setItemPrice(item.ItemId, newItemPrice)
|
await itemStore.setItemPrice(item.ItemId, newItemPrice)
|
||||||
await release()
|
await release()
|
||||||
}
|
}
|
||||||
}, [shouldPushNewItemPrice])
|
}, [shouldPushNewItemPrice, authUserStore])
|
||||||
|
|
||||||
|
useAsyncEffect(async () => {
|
||||||
|
if (authUserStore.Id === -1) {
|
||||||
|
const release = await itemTableListRowMutex.acquire()
|
||||||
|
await authUserStore.sync()
|
||||||
|
await release()
|
||||||
|
}
|
||||||
|
}, [authUserStore])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
@@ -79,7 +91,7 @@ export const ItemTableListRow = ({item}: ItemTableListRowProps) => {
|
|||||||
price: {Math.trunc(item.ItemPrice * 100) / 100}
|
price: {Math.trunc(item.ItemPrice * 100) / 100}
|
||||||
</ItemFieldContainer>
|
</ItemFieldContainer>
|
||||||
</ItemOverviewContainer>
|
</ItemOverviewContainer>
|
||||||
{shouldShowDetails && (
|
{shouldShowDetails && authUserStore.Admin && (
|
||||||
<>
|
<>
|
||||||
<ItemDetailsContainer>
|
<ItemDetailsContainer>
|
||||||
<h1 className="text-xl">Set Item Price</h1>
|
<h1 className="text-xl">Set Item Price</h1>
|
||||||
|
|||||||
@@ -1,11 +1,29 @@
|
|||||||
|
'use client'
|
||||||
import Link from "next/link"
|
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 = () => {
|
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 (
|
return (
|
||||||
<nav>
|
<nav>
|
||||||
<div className="flex items-center justify-center">
|
<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="/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>
|
<Link className=" pl-7 pr-7 pt-3 pb-3 hover:bg-purple-950" href="/items">Items</Link>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
'for client'
|
||||||
import { useItemStore } from "../providers/ItemsProvider"
|
import { useItemStore } from "../providers/ItemsProvider"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import useAsyncEffect from "use-async-effect"
|
import useAsyncEffect from "use-async-effect"
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import { useOrderStore } from "../providers/OrderProvider"
|
import { useOrderStore } from "../providers/OrderProvider"
|
||||||
import { useShallow } from "zustand/shallow"
|
import { useShallow } from "zustand/shallow"
|
||||||
import useAsyncEffect from "use-async-effect"
|
import useAsyncEffect from "use-async-effect"
|
||||||
import { OrderTableRow } from "./OrderTableRow"
|
|
||||||
import { Mutex } from "async-mutex"
|
import { Mutex } from "async-mutex"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
|
import { OrderTableRow } from "./OrderTableRow"
|
||||||
|
|
||||||
type OrderTableProps = {
|
type OrderTableProps = {
|
||||||
page: number,
|
page: number,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
'for client'
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import { OrderItemTable } from "./OrderItemTable"
|
import { OrderItemTable } from "./OrderItemTable"
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useUserStore } from "../providers/UsersProvider"
|
|||||||
import useAsyncEffect from "use-async-effect"
|
import useAsyncEffect from "use-async-effect"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import { useRef, useState } from "react"
|
import { useRef, useState } from "react"
|
||||||
|
import { useCurrentAuthenticatedUserStore } from "../providers"
|
||||||
|
import { Mutex } from "async-mutex"
|
||||||
|
|
||||||
type UserTableProps = {
|
type UserTableProps = {
|
||||||
page: number
|
page: number
|
||||||
@@ -35,6 +37,8 @@ const UserTableRow = styled.tr`
|
|||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const userTableMutex = new Mutex()
|
||||||
|
|
||||||
export const UserTable = ({page}: UserTableProps) => {
|
export const UserTable = ({page}: UserTableProps) => {
|
||||||
|
|
||||||
const userStore = useUserStore(useShallow((state) => ({
|
const userStore = useUserStore(useShallow((state) => ({
|
||||||
@@ -43,26 +47,38 @@ export const UserTable = ({page}: UserTableProps) => {
|
|||||||
console.log(page)
|
console.log(page)
|
||||||
|
|
||||||
const [callLock, setCallLock] = useState<boolean>(false)
|
const [callLock, setCallLock] = useState<boolean>(false)
|
||||||
|
const authUserStore = useCurrentAuthenticatedUserStore(useShallow((state) => state))
|
||||||
|
console.log(authUserStore)
|
||||||
const callLockRef = useRef(callLock)
|
const callLockRef = useRef(callLock)
|
||||||
useAsyncEffect(async () => {
|
useAsyncEffect(async () => {
|
||||||
if(!callLockRef.current) {
|
if(!callLockRef.current && authUserStore.Admin) {
|
||||||
callLockRef.current = true
|
callLockRef.current = true
|
||||||
setCallLock(true)
|
setCallLock(true)
|
||||||
await userStore.sync(page)
|
await userStore.sync(page)
|
||||||
callLockRef.current = false
|
callLockRef.current = false
|
||||||
setCallLock(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)
|
console.log(userStore.tableUsers)
|
||||||
return (
|
return authUserStore.Admin && (
|
||||||
<UserTableStyle>
|
<UserTableStyle>
|
||||||
<UserTableHead>
|
<UserTableHead>
|
||||||
|
<tr>
|
||||||
<UserTH>id</UserTH>
|
<UserTH>id</UserTH>
|
||||||
<UserTH>name</UserTH>
|
<UserTH>name</UserTH>
|
||||||
<UserTH>position</UserTH>
|
<UserTH>position</UserTH>
|
||||||
<UserTH>active</UserTH>
|
<UserTH>active</UserTH>
|
||||||
<UserTH>admin</UserTH>
|
<UserTH>admin</UserTH>
|
||||||
|
</tr>
|
||||||
</UserTableHead>
|
</UserTableHead>
|
||||||
<UserTableBody>
|
<UserTableBody>
|
||||||
{userStore.tableUsers.map((u) => (
|
{userStore.tableUsers.map((u) => (
|
||||||
@@ -70,18 +86,18 @@ export const UserTable = ({page}: UserTableProps) => {
|
|||||||
<UserTableItem>{u.Id}</UserTableItem>
|
<UserTableItem>{u.Id}</UserTableItem>
|
||||||
<UserTableItem>{u.Name}</UserTableItem>
|
<UserTableItem>{u.Name}</UserTableItem>
|
||||||
<UserTableItem>{u.JobPosition}</UserTableItem>
|
<UserTableItem>{u.JobPosition}</UserTableItem>
|
||||||
<UserTableItem><input type="checkbox" defaultValue={u.Active ? "yes" : "no"} onChange={async (e) => {
|
<UserTableItem><input type="checkbox" onChange={async (e) => {
|
||||||
if(u.Active)
|
if(u.Active)
|
||||||
await userStore.deactivateUser(u.Id)
|
await userStore.deactivateUser(u.Id)
|
||||||
else
|
else
|
||||||
await userStore.activateUser(u.Id)
|
await userStore.activateUser(u.Id)
|
||||||
}}/></UserTableItem>
|
}} checked={u.Active}/></UserTableItem>
|
||||||
<UserTableItem><input type="checkbox" value={u.Admin ? "yes" : "no"} onChange={async (e) => {
|
<UserTableItem><input type="checkbox" onChange={async (e) => {
|
||||||
if(u.Admin)
|
if(u.Admin)
|
||||||
await userStore.demoteUser(u.Id)
|
await userStore.demoteUser(u.Id)
|
||||||
else
|
else
|
||||||
await userStore.promoteUser(u.Id)
|
await userStore.promoteUser(u.Id)
|
||||||
}}/></UserTableItem>
|
}} checked={u.Admin}/></UserTableItem>
|
||||||
</UserTableRow>))}
|
</UserTableRow>))}
|
||||||
</UserTableBody>
|
</UserTableBody>
|
||||||
</UserTableStyle>
|
</UserTableStyle>
|
||||||
|
|||||||
@@ -1,10 +1,71 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import { useState } from "react"
|
||||||
import { ItemTableList } from "../components/ItemTableList"
|
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 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 (
|
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 () => {
|
sync: async () => {
|
||||||
const authUser = await GetCurrentUser()
|
const authUser = await GetCurrentUser()
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
...authUser,
|
...state,
|
||||||
...state
|
...authUser
|
||||||
}))
|
}))
|
||||||
return authUser
|
return authUser
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user