Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Home from "./pages/Home";
import Sidebar from "./Sidebar";
import "./styles/style.css";
import Settings from "./pages/Settings";
import Monitoring from "./pages/Monitoring";
import Certification from "./pages/Certifiaction";

export default function App() {
return (
Expand All @@ -13,6 +15,8 @@ export default function App() {
<Routes>
<Route path="/" element={<Home />} />
<Route path="/settings" element={<Settings />} />
<Route path="/monitoring" element={<Monitoring />} />
<Route path="/certification" element={<Certification />} />
</Routes>
</div>
</div>
Expand Down
21 changes: 16 additions & 5 deletions src/Sidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link } from "react-router-dom";
import { Link, useLocation } from "react-router-dom";
import MenuIcon from "./assets/menu_icon.svg?react";
import HomeIcon from "./assets/home_icon.svg?react";
import MonitorIcon from "./assets/monitor_icon.svg?react";
Expand All @@ -7,12 +7,23 @@ import AwardIcon from "./assets/award_icon.svg?react";
import BellIcon from "./assets/bell_icon.svg?react";
import CloseIcon from "./assets/close_icon.svg?react";
import Logo from "./assets/temp_logo.svg?react";
import { useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";

export default function Sidebar() {
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(true);
const alram_count = 3;
const location = useLocation();
const [currentPage, setCurrentPage] = useState("Home");
useEffect(() => {
if (location.pathname === "/") setCurrentPage("Home");
else if (location.pathname.startsWith("/monitoring"))
setCurrentPage("Monitor");
else if (location.pathname.startsWith("/settings"))
setCurrentPage("Sensor");
else if (location.pathname.startsWith("/certification"))
setCurrentPage("Certification");
}, [location.pathname]);

return (
<aside className={isOpen ? "sidebar-open" : "sidebar-close"}>
{!isOpen && (
Expand Down Expand Up @@ -74,7 +85,7 @@ export default function Sidebar() {
className="icon side-opt"
onClick={() => setCurrentPage("Monitor")}
>
<Link>
<Link to="/monitoring">
<MonitorIcon
fill={currentPage === "Monitor" ? "#608DFF" : "#FFF"}
width="1.5rem"
Expand Down Expand Up @@ -118,7 +129,7 @@ export default function Sidebar() {
className="icon side-opt"
onClick={() => setCurrentPage("Certification")}
>
<Link>
<Link to="/certification">
<AwardIcon
stroke={currentPage === "Certification" ? "#608DFF" : "#FFF"}
width="1.5rem"
Expand Down
13 changes: 13 additions & 0 deletions src/assets/edit_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions src/components/FacilityModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useState } from "react";
import XIcon from "../assets/x_icon.svg?react";

export default function FacilityModal({ isOpen, onClose, zoneInfo, onUpdate }) {
if (isOpen) {
const [newFacility, setNewFacility] = useState("");
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-box" onClick={(e) => e.stopPropagation()}>
<div onClick={onClose}>
<XIcon width="1.5rem" height="1.5rem" />
</div>
<div className="modal-contents">
<span>[{zoneInfo}]의 설비 추가</span>
<div className="input-flex">
<span>설비 이름</span>
<input
type="text"
value={newFacility}
onChange={(e) => {
setNewFacility(e.target.value);
}}
></input>
</div>
<div className="button-flex">
<button onClick={() => onUpdate(newFacility)}>추가</button>
</div>
</div>
</div>
</div>
);
} else {
return null;
}
}
11 changes: 11 additions & 0 deletions src/components/MonitorBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function MonitorBox({ zone }) {
return (
<div
className={`monitor-box moving-box ${
zone.level == 0 ? "" : zone.level == 1 ? "warn" : "urgent"
}`}
>
<p>{zone.title}</p>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from "react";
import XIcon from "../assets/x_icon.svg?react";

export default function Modal({ isOpen, onClose, sensorInfo, onUpdate }) {
export default function SensorModal({ isOpen, onClose, sensorInfo, onUpdate }) {
if (isOpen) {
const { zoneName, sensorName, thres } = sensorInfo;
const [newThres, setNewThres] = useState(thres);
Expand Down
80 changes: 60 additions & 20 deletions src/components/ZoneInfoBox.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { useState } from "react";
import ToolIcon from "../assets/tool_icon.svg?react";
export default function ZoneInfoBox({ zone, modalBtn, onAddZone = null }) {
const { title, env_sensor = [], fac_sensor = [], master = "" } = zone;
export default function ZoneInfoBox({
zone,
sensorModalBtn,
facilityModalBtn,
onAddZone = null,
}) {
const { title, env_sensor = [], facility = [], master = "" } = zone;
const [isOpen, setIsOpen] = useState(false);
const addZone = zone === "공간 추가";
const [newZone, setNewZone] = useState("");
const [facilityInfoOpen, setFacilityInfoOpen] = useState({});

const toggleFacility = (i) => {
setFacilityInfoOpen((prev) => ({
...prev,
[i]: !prev[i],
}));
};

return (
<div className="box-wrapper">
<div
Expand All @@ -27,14 +41,18 @@ export default function ZoneInfoBox({ zone, modalBtn, onAddZone = null }) {
{env_sensor.length !== 0 &&
env_sensor.map((sen, i) => (
<div className="list-text" key={i}>
{/* <div>{sen.name}</div> */}
<div>
{sen.name}
<span className="sensor-id"> ({sen.id})</span> {/* ← 추가 */}
{sen.name}
<span className="sensor-id">
{" "}
(UA10T-TEM-24060890)
</span>{" "}
</div>
<span className="dash-line"></span>현재 설정값:{" "}
<div>{sen.thres}</div>
<span onClick={() => modalBtn(title, sen.name, sen.thres)}>
<span className="dash-line"></span>
<div>현재 설정값: {sen.thres}</div>
<span
onClick={() => sensorModalBtn(title, sen.name, sen.thres)}
>
<ToolIcon
className="thres-setting"
width="1.3rem"
Expand All @@ -47,21 +65,43 @@ export default function ZoneInfoBox({ zone, modalBtn, onAddZone = null }) {
</div>
<div className="sensorlist">
<div className="sensorlist-underbar">설비 관리 센서</div>
{fac_sensor.length === 0 && <p>설비 관리 센서가 없습니다</p>}
{fac_sensor.length !== 0 &&
fac_sensor.map((sen, i) => (
<div className="list-text" key={i}>
{/* <div>{sen}</div> */}
<div>{sen.name}
<span className="sensor-id"> ({sen.id})</span>
{facility.length === 0 && <p>등록된 설비가 없습니다</p>}
{facility.length !== 0 &&
facility.map((f, i) => (
<div key={i}>
{/* 설비 목록 */}
<div className="list-text">
<div>{f.name}</div>
<span className="dash-line"></span>
<span className="arrow" onClick={() => toggleFacility(i)}>
{facilityInfoOpen[i] ? "▲" : "▼"}
</span>
</div>
<span className="dash-line"></span>현재 설정값:
<div>{sen.thres}</div>
<span onClick={() => modalBtn(title, sen.name, sen.thres)}>
<ToolIcon className="thres-setting" width="1.3rem" fill="gray" stroke="gray" />
</span>
{/* 설비 센서 목록 */}
{facilityInfoOpen[i] && (
<div style={{ margin: "0 1rem" }}>
{(!Array.isArray(f.fac_sensor) ||
f.fac_sensor.length === 0) && (
<p>설비 관리용 센서가 없습니다</p>
)}
{f.fac_sensor?.length !== 0 &&
f.fac_sensor?.map((s, i) => (
<p key={i}>
{s.name} ({s.id})
</p>
))}
</div>
)}
</div>
))}
<p>
<button
className="no-flex-button"
onClick={() => facilityModalBtn(title)}
>
+ 설비 등록
</button>
</p>
</div>
<div className="sensorlist">
<div className="sensorlist-underbar">담당자</div>
Expand Down
27 changes: 27 additions & 0 deletions src/mock_data/mock_zonelist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* mock data */
const mockZoneList = [
{
title: "보일러실",
env_sensor: [
{ name: "온도 센서", thres: 60 },
{ name: "습도 센서", thres: 75 },
],
fac_sensor: [],
master: "김00",
level: 2,
},
{
title: "휴게실",
env_sensor: [],
fac_sensor: ["진동 센서"],
master: "윤00",
level: 0
},
{ title: "테스트룸A", env_sensor: [], fac_sensor: [], master: "정00", level: 0 },
{ title: "테스트룸B", env_sensor: [], fac_sensor: [], master: "강00", level: 0 },
{ title: "테스트룸C", env_sensor: [], fac_sensor: [], master: "이00", level: 0 },
{ title: "테스트룸D", env_sensor: [], fac_sensor: [], master: "박00", level: 0 },
];


export default mockZoneList;
7 changes: 7 additions & 0 deletions src/pages/Certifiaction.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Certification() {
return (
<>
<h1>Certifiaction</h1>
</>
);
}
31 changes: 31 additions & 0 deletions src/pages/Monitoring.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect, useState } from "react";
import MonitorBox from "../components/MonitorBox";
import mockZoneList from "../mock_data/mock_zonelist";

export default function Monitoring() {
const [zoneList, setZoneList] = useState([]);
// useEffect(() => {
// fetch("../mock_data/mock_zonelist.json")
// .then((res) => {
// setZoneList(res.data);
// })
// .catch((err) => {
// console.error("데이터 불러오기 실패", err);
// });
// }, []);
useEffect(() => {
setZoneList(mockZoneList);
});
return (
<>
<h1>Monitoring</h1>
<div className="monitor-body">
<div>
{zoneList.map((z, i) => (
<MonitorBox zone={z} key={i} />
))}
</div>
</div>
</>
);
}
Loading
Loading