added SelectCategoryModal
Build and Test / build-and-test-backend (push) Successful in 28s
Build and Test / build-and-test-frontend (push) Failing after 33s

This commit is contained in:
wt
2025-10-08 13:36:22 +07:00
parent 582ab5e7b9
commit 5706a85631
3 changed files with 187 additions and 26 deletions
@@ -9,6 +9,7 @@ import {
Row,
Col,
} from "react-bootstrap";
import SelectCategoryModal from "../../modals/SelectCategoryModal/SelectCategoryModal";
// import styles from "./HistoryModal.module.css";
const AddOperationModal = ({ variant }) => {
@@ -20,6 +21,12 @@ const AddOperationModal = ({ variant }) => {
const [isExpense, setIsExpense] = useState(true);
const [isNoteVisible, setIsNoteVisible] = useState(false);
const [amount, setAmount] = useState();
const [selectedCategory, setSelectedCategory] = useState({
id: null,
title: "Category",
icon: "?",
description: "Tap to select",
});
return (
<>
{variant ? (
@@ -104,30 +111,11 @@ const AddOperationModal = ({ variant }) => {
>
Appointment
</h3>
<Button variant={theme} className="w-100 mt-3">
<div className="d-flex flex-row gap-3 p-2">
<div
className="p-2 justify-content-start align-items-start d-flex flex-column"
style={{ fontSize: "30px" }}
>
<div>&#128512;</div>
</div>
<div className="d-flex flex-column p-0 justify-content-center align-items-start w-100">
<h3
className="mb-0 fw-bolder"
style={{ fontSize: "1.1rem", fontWeight: 700 }}
>
-63.00 ₽
</h3>
<div
className="text-muted small mb-1"
style={{ fontSize: "0.8rem" }}
>
Transport
</div>
</div>
</div>
</Button>
<SelectCategoryModal
categoriestype={isIncome ? "income" : "expense"}
selectedCategory={selectedCategory}
setSelectedCategory={setSelectedCategory}
/>
</div>
<Card className="m-2">
<Card.Body>
@@ -3,10 +3,10 @@ import { Button } from "react-bootstrap";
import styles from "./CategorySign.module.css";
import classNames from "classnames";
const CategorySign = ({ icon, title, subcategories }) => {
const CategorySign = ({ icon, title, subcategories, ...props }) => {
const { theme } = useTheme();
return (
<Button variant={theme} className="w-100 mt-3">
<Button variant={theme} className="w-100 mt-3" {...props}>
<div>
<div className="d-flex flex-row gap-3 p-2">
<div
@@ -0,0 +1,173 @@
import { useEffect, useState, useMemo, useCallback } from "react";
import { useTheme } from "../../contexts/ThemeContext";
import {
Modal,
Button,
Form,
InputGroup,
Tabs,
Tab,
Dropdown,
DropdownButton,
} from "react-bootstrap";
import AddCategoryModal from "../../modals/AddCategoryModal/AddCategoryModal";
import CategorySign from "../CategoriesModal/components/CategorySign/CategorySign";
import fetchCategories from "../../logic/category/GetAllCategories";
const SelectCategoryModal = ({
categoriestype,
selectedCategory,
setSelectedCategory,
}) => {
const { theme } = useTheme();
const [show, setShow] = useState(false);
// const [selectedCategory, setSelectedCategory] = useState({
// id: null,
// title: "Category",
// icon: "?",
// description: "Tap to select",
// });
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = useCallback((e) => {
setSearchTerm(e.target.value);
}, []);
let [expenseCategories, setExpenseCategories] = useState([]);
const [incomeCategories, setIncomeCategories] = useState([]);
useEffect(() => {
fetchCategories().then((data) => {
setExpenseCategories(
data.filter((category) => category.type === "expense"),
);
setIncomeCategories(
data.filter((category) => category.type === "income"),
);
console.log(data);
});
}, [show]);
const filteredExpenseCategories = useMemo(() => {
if (!searchTerm) return expenseCategories;
const term = searchTerm.toLowerCase();
return expenseCategories.filter((category) =>
category.title.toLowerCase().includes(term),
);
}, [expenseCategories, searchTerm]);
const filteredIncomeCategories = useMemo(() => {
if (!searchTerm) return incomeCategories;
const term = searchTerm.toLowerCase();
return incomeCategories.filter((category) =>
category.title.toLowerCase().includes(term),
);
}, [incomeCategories, searchTerm]);
const handleCategorySelect = (category) => {
const newSelectedCategory = {
id: category.id,
title: category.title,
icon: category.icon,
description:
category.type === "income" ? "Income category" : "Expense category",
};
setSelectedCategory(newSelectedCategory);
setShow(false);
};
return (
<>
<Button variant={theme} className="w-100 mt-3" onClick={handleShow}>
<div className="d-flex flex-row gap-3 p-2">
<div
className="p-2 justify-content-start align-items-start d-flex flex-column"
style={{ fontSize: "30px" }}
>
<div>{selectedCategory.icon ? selectedCategory.icon : "?"}</div>
</div>
<div className="d-flex flex-column p-0 justify-content-center align-items-start w-100">
<h3
className="mb-0 fw-bolder"
style={{ fontSize: "1.1rem", fontWeight: 700 }}
>
{selectedCategory.title ? selectedCategory.title : "Category"}
</h3>
<div
className="text-muted small mb-1"
style={{ fontSize: "0.8rem" }}
>
{selectedCategory.description
? selectedCategory.description
: "Tap to select"}
</div>
</div>
</div>
</Button>
<Modal show={show} onHide={handleClose} fullscreen={true}>
<Modal.Header>
<div className="d-flex flex-column w-100 gap-2">
<div className="d-flex align-items-center justify-content-between">
<Button
variant={theme}
onClick={handleClose}
className="d-flex justify-content-between gap-2"
>
<div style={{ transform: "rotate(180deg)" }}>&#10095;</div>
<div>Back</div>
</Button>
<Modal.Title>Appointment</Modal.Title>
<div></div>
<DropdownButton title="&#9776;" variant={theme} drop="start">
<Dropdown.Item className="p-0">
<AddCategoryModal
className="w-100"
style={{ paddingLeft: "0" }}
type={categoriestype}
showParent={handleShow}
closeParent={handleClose}
/>
</Dropdown.Item>
<Dropdown.Item>Reorder</Dropdown.Item>
</DropdownButton>
</div>
<InputGroup className="mb-3">
<InputGroup.Text id="basic-addon1">
<div style={{ transform: "rotate(90deg)" }}>&#9740;</div>
</InputGroup.Text>
<Form.Control
placeholder="Search"
aria-label="Search"
aria-describedby="basic-addon1"
value={searchTerm}
onChange={handleSearch}
/>
</InputGroup>
</div>
</Modal.Header>
<Modal.Body className="p-0">
{categoriestype === "income"
? filteredIncomeCategories.map((category) => (
<CategorySign
key={`${category.id}`}
icon={category.icon}
title={category.title}
subcategories={
category.subcategories ? category.subcategories : []
}
onClick={() => handleCategorySelect(category)}
/>
))
: filteredExpenseCategories.map((category) => (
<CategorySign
key={`${category.id}`}
icon={category.icon}
title={category.title}
subcategories={
category.subcategories ? category.subcategories : []
}
onClick={() => handleCategorySelect(category)}
/>
))}
</Modal.Body>
</Modal>
</>
);
};
export default SelectCategoryModal;