Fix updating of user roles

Fix adding of items
This commit is contained in:
Nico 2025-11-23 01:41:15 -08:00
parent d9c4a2caf9
commit f30474cb5d
8 changed files with 56 additions and 21 deletions

View File

@ -6,6 +6,12 @@ exports.getList = async (req, res) => {
res.json(items); res.json(items);
}; };
exports.getItemByName = async (req, res) => {
const { itemName } = req.query;
const item = await List.getItemByName(itemName);
res.json(item);
}
exports.addItem = async (req, res) => { exports.addItem = async (req, res) => {
const { itemName, quantity } = req.body; const { itemName, quantity } = req.body;

View File

@ -14,10 +14,10 @@ exports.getAllUsers = async (req, res) => {
exports.updateUserRole = async (req, res) => { exports.updateUserRole = async (req, res) => {
try { try {
const { id } = req.params; const { id, role } = req.body;
const { role } = req.body;
if (!Object.values(ROLES).includes(role)) console.log(`Updating user ${id} to role ${role}`);
if (!Object.values(User.ROLES).includes(role))
return res.status(400).json({ error: "Invalid role" }); return res.status(400).json({ error: "Invalid role" });
const updated = await User.updateUserRole(id, role); const updated = await User.updateUserRole(id, role);

View File

@ -8,23 +8,37 @@ exports.getUnboughtItems = async () => {
return result.rows; return result.rows;
}; };
exports.getItemByName = async (itemName) => {
exports.addOrUpdateItem = async (item_name, quantity) => {
const result = await pool.query( const result = await pool.query(
"SELECT id, bought FROM grocery_list WHERE item_name = $1", "SELECT * FROM grocery_list WHERE item_name ILIKE $1",
[item_name] [itemName]
);
return result.rows[0] || null;
};
exports.addOrUpdateItem = async (itemName, quantity) => {
const result = await pool.query(
"SELECT id, bought FROM grocery_list WHERE item_name ILIKE $1",
[itemName]
); );
if (result.rowCount > 0) { if (result.rowCount > 0) {
await pool.query( await pool.query(
"UPDATE grocery_list SET quantity = $1, bought = FALSE WHERE id = $2", `UPDATE grocery_list
SET quantity = $1,
bought = FALSE
WHERE id = $2`,
[quantity, result.rows[0].id] [quantity, result.rows[0].id]
); );
return result.rows[0].id; return result.rows[0].id;
} else { } else {
const insert = await pool.query( const insert = await pool.query(
"INSERT INTO grocery_list (item_name, quantity) VALUES ($1, $2) RETURNING id", `INSERT INTO grocery_list
[item_name, quantity] (item_name, quantity)
VALUES ($1, $2) RETURNING id`,
[itemName, quantity]
); );
return insert.rows[0].id; return insert.rows[0].id;
} }

View File

@ -7,8 +7,9 @@ const User = require("../models/user.model");
router.get("/", auth, requireRole(ROLES.VIEWER, ROLES.EDITOR, ROLES.ADMIN), controller.getList); router.get("/", auth, requireRole(...Object.values(ROLES)), controller.getList);
router.get("/suggest", auth, requireRole(ROLES.VIEWER, ROLES.EDITOR, ROLES.ADMIN), controller.getSuggestions); router.get("/item-by-name", auth, requireRole(...Object.values(ROLES)), controller.getItemByName);
router.get("/suggest", auth, requireRole(...Object.values(ROLES)), controller.getSuggestions);
router.post("/add", auth, requireRole(ROLES.EDITOR, ROLES.ADMIN), controller.addItem); router.post("/add", auth, requireRole(ROLES.EDITOR, ROLES.ADMIN), controller.addItem);

View File

@ -1,6 +1,7 @@
import api from "./axios"; import api from "./axios";
export const getList = () => api.get("/list"); export const getList = () => api.get("/list");
export const addItem = (itemName, quantiy) => api.post("/list/add", { itemName, quantiy }); export const getItemByName = (itemName) => api.get("/list/item-by-name", { params: { itemName: itemName } });
export const addItem = (itemName, quantity) => api.post("/list/add", { itemName, quantity });
export const markBought = (id) => api.post("/list/mark-bought", { id }); export const markBought = (id) => api.post("/list/mark-bought", { id });
export const getSuggestions = (query) => api.get("/list/suggest", { params: { query: query } }); export const getSuggestions = (query) => api.get("/list/suggest", { params: { query: query } });

View File

@ -1,6 +1,6 @@
import api from "./axios"; import api from "./axios";
export const getAllUsers = () => api.get("/admin/users"); export const getAllUsers = () => api.get("/admin/users");
export const updateRole = (id, role) => api.put(`/admin/users/${id}/role`, { role }); export const updateRole = (id, role) => api.put(`/admin/users`, { id, role });
export const deleteUser = (id) => api.delete(`/admin/users/${id}`); export const deleteUser = (id) => api.delete(`/admin/users/${id}`);
export const checkIfUserExists = (username) => api.get(`/users/exists`, { params: { username: username } }); export const checkIfUserExists = (username) => api.get(`/users/exists`, { params: { username: username } });

View File

@ -17,7 +17,8 @@ export default function AdminPanel() {
const changeRole = async (id, role) => { const changeRole = async (id, role) => {
const updated = await updateRole(id, role); const updated = await updateRole(id, role);
setUsers(users.map(u => (u.id === id ? updated.data : u))) if (updated.status !== 200) return;
loadUsers();
} }
return ( return (

View File

@ -1,5 +1,5 @@
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { addItem, getList, getSuggestions, markBought } from "../api/list"; import { addItem, getItemByName, getList, getSuggestions, markBought } from "../api/list";
import { ROLES } from "../constants/roles"; import { ROLES } from "../constants/roles";
import { AuthContext } from "../context/AuthContext"; import { AuthContext } from "../context/AuthContext";
import "../styles/GroceryList.css"; import "../styles/GroceryList.css";
@ -12,6 +12,7 @@ export default function GroceryList() {
const [sortMode, setSortMode] = useState("az"); const [sortMode, setSortMode] = useState("az");
const [showSuggestions, setShowSuggestions] = useState(false);
const [itemName, setItemName] = useState(""); const [itemName, setItemName] = useState("");
const [quantity, setQuantity] = useState(1); const [quantity, setQuantity] = useState(1);
const [suggestions, setSuggestions] = useState([]); const [suggestions, setSuggestions] = useState([]);
@ -57,10 +58,8 @@ export default function GroceryList() {
} }
try { try {
console.log("Getting suggestions for:", text);
let suggestions = await getSuggestions(text); let suggestions = await getSuggestions(text);
suggestions = suggestions.data.map(s => s.item_name); suggestions = suggestions.data.map(s => s.item_name);
console.log(`Suggestions: ${suggestions}`);
setSuggestions(suggestions); setSuggestions(suggestions);
} catch { } catch {
setSuggestions([]); setSuggestions([]);
@ -70,8 +69,20 @@ export default function GroceryList() {
const handleAdd = async (e) => { const handleAdd = async (e) => {
e.preventDefault(); e.preventDefault();
if (!itemName.trim()) return; if (!itemName.trim()) return;
let newQuantity = quantity;
await addItem(itemName, quantity); const item = await getItemByName(itemName);
if (item) {
let currentQuantity = item.data.quantity;
const yes = window.confirm(
`Item "${itemName}" already exists in the list. Do you want to update its quantity from ${currentQuantity} to ${currentQuantity + newQuantity}?`
);
if (!yes) return;
newQuantity += currentQuantity;
}
await addItem(itemName, newQuantity);
setItemName(""); setItemName("");
setQuantity(1); setQuantity(1);
@ -93,7 +104,6 @@ export default function GroceryList() {
return ( return (
<div className="glist-body"> <div className="glist-body">
<div className="glist-container"> <div className="glist-container">
<h1 className="glist-title">Costco Grocery List</h1> <h1 className="glist-title">Costco Grocery List</h1>
{/* Sorting dropdown */} {/* Sorting dropdown */}
@ -117,9 +127,11 @@ export default function GroceryList() {
placeholder="Item name" placeholder="Item name"
value={itemName} value={itemName}
onChange={(e) => handleSuggest(e.target.value)} onChange={(e) => handleSuggest(e.target.value)}
onBlur={() => setTimeout(() => setShowSuggestions(false), 150)}
onClick={() => setShowSuggestions(true)}
/> />
{suggestions.length > 0 && ( {showSuggestions && suggestions.length > 0 && (
<ul className="glist-suggest-box"> <ul className="glist-suggest-box">
{suggestions.map((s, i) => ( {suggestions.map((s, i) => (
<li <li