최정우 최정우 2023-04-04
230404 최정우 사용자 관리 커밋
@af59b089d58856246b5511eedcc014407fa1333f
client/resources/css/reset.css
--- client/resources/css/reset.css
+++ client/resources/css/reset.css
@@ -82,6 +82,17 @@
   border: 1px solid #d8d3c7;
 }
 
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+  -webkit-appearance: none;
+  margin: 0;
+}
+
+/* Firefox */
+input[type=number] {
+  -moz-appearance: textfield;
+}
+
 input[type="button"]{
   width: 100%;
   background: none;
@@ -90,9 +101,11 @@
 }
 
 select{
-  width: 32%;
+  /* width: 32%; */
+  width: 100%;
   border-radius: 0.5rem;
   border: 1px solid #d8d3c7;
+  padding: 1rem;
 }
 
 select:last-child{
@@ -108,4 +121,15 @@
 textarea{
   width: 100%;
   height: 150px;
-}
(파일 끝에 줄바꿈 문자 없음)
+}
+
+a {
+  cursor: pointer;
+}
+
+a.active {
+  color: #0089ff;
+  font-weight: bold;
+  font-size: 1.1em;
+}
+
 
client/resources/js/CommonUtil.js (added)
+++ client/resources/js/CommonUtil.js
@@ -0,0 +1,507 @@
+/**
+ * @author 최정우
+
+ * @since 2019.12.06
+ *
+ * 공통 자바스크립트 Util입니다.
+ */
+
+const CommonUtil = (function () {
+
+	var _utils = {
+		/**
+		 * 빈 객체 여부
+		 */
+		isEmpty: function (data) {
+			if (data === undefined || data === null || data === "" || data.length === 0 || (data.constructor == Object && Object.keys(data).length === 0)) {
+				if ((typeof data) === "number") {
+					return false
+				} else {
+					return true;
+				}
+			} else {
+				return false;
+			}
+		},
+
+		/**
+		 * empty to null
+		 */
+		toNull: function (data) {
+			if(data === undefined || data === "") {
+				try {
+					data = null;
+					return data;
+				} catch (e) {
+					console.log("commonUtil.js - empty to null convert error : ", e);
+					return data;
+				}
+			} else {
+				return data;
+			}
+		},
+
+		/**
+		 * string to JSON
+		 */
+		toJson: function (data) {
+			if ("string" === (typeof data)) {
+				try {
+					return JSON.parse(data);
+				} catch (e) {
+					console.log("commonUtil.js - string to json convert error : ", e);
+					return data;
+				}
+			} else {
+				return data;
+			}
+		},
+
+		/**
+		 * string to JSON
+		 */
+		toJson: function (data) {
+			if ("string" === (typeof data)) {
+				try {
+					return JSON.parse(data);
+				} catch (e) {
+					console.log("commonUtil.js - string to json convert error : ", e);
+					return data;
+				}
+			} else {
+				return data;
+			}
+		},
+
+		/**
+		 * JSON to string
+		 */
+		toString: function (data) {
+			try {
+				return JSON.parse(data);
+			} catch (e) {
+				console.log("commonUtil.js - json to string convert error : ", e);
+				return data;
+			}
+		},
+
+		/**
+		 * 다중 separator split
+		 */
+		split: function (text, separator) {
+			var words = [];
+			if (this.isEmpty(text) == false && this.isEmpty(separator) == false && separator.length > 0) {
+				words.push(text);
+				for (var i = 0; i < separator.length; i++) {
+					var subWords = [];
+					for (var j = 0; j < words.length; j++) {
+						if (this.isEmpty(words[j]) == false && this.isEmpty(separator[i]) == false) {
+							subWords = subWords.concat(words[j].split(separator[i]));
+						} else {
+							if (words[j] == false) {
+								subWords.push(words[j]);
+							} else {
+								continue;
+							}
+						}
+					}
+					words = subWords;
+				}
+				return words;
+			} else {
+				if (this.isEmpty(text) == false) {
+					words.push(text);
+				}
+				return words;
+			}
+		},
+
+		/**
+		 * 객체 깊은 복사
+		 */
+		copyObject: function (obj) {
+			if (obj === null || typeof(obj) !== 'object') return obj;
+
+			try {
+				return JSON.parse(JSON.stringify(obj));
+			} catch (e) {
+				console.log("commonUtil.js - copyObject error : ", e);
+				return null;
+			}
+		},
+		/**
+		 * 날짜 + 시간 구하기
+		 *
+		 *
+
+		 */
+		getDateTime : function () {
+			return this.getDate()+ " " + this.getFullTime();
+		},
+
+		/**
+		 * 날짜 구하기
+		 *
+		 * param 설명
+		 *
+		 * options = {
+		 * 	 addYear(Integer),
+		 *   addMonth(Integer),
+		 *   addDay(Integer),
+		 *   separator(String)
+		 * }
+		 */
+		getDate: function (options) {
+
+			if (this.isEmpty(options) == true) {
+				options = {
+					addYear: 0,
+					addMonth: 0,
+					addDay: 0,
+					separator: '-'
+				}
+			} else {
+				options.addYear = options.addYear || 0;
+				options.addMonth = options.addMonth || 0;
+				options.addDay = options.addDay || 0;
+				options.separator = options.separator || '-';
+			}
+
+			var date = new Date();
+			date.setFullYear(date.getFullYear() + options.addYear);
+			date.setMonth(date.getMonth() + options.addMonth);
+			date.setDate(date.getDate() + options.addDay);
+
+			var yyyy = date.getFullYear();
+			var mm = date.getMonth() + 1;
+			var dd = date.getDate();
+
+			return yyyy + options.separator + this.prefixZero(mm, 2) + options.separator + this.prefixZero(dd, 2);
+		},
+
+		/**
+		 * 현재 년도 조회
+		 */
+		getYear: function () {
+			var date = new Date();
+			return date.getFullYear();
+		},
+
+		/**
+		 * 현재 월 조회
+		 */
+		getMonth: function () {
+			var date = new Date();
+			return date.getMonth() + 1;
+		},
+
+		/**
+		 * 현재 월 조회
+		 */
+		getFullMonth: function () {
+			var date = new Date();
+			return this.prefixZero((date.getMonth() + 1), 2);
+		},
+
+		/**
+		 * 현재 일 조회
+		 */
+		getDay: function () {
+			var date = new Date();
+			return date.getDate();
+		},
+
+		/**
+		 * 현재 일 조회
+		 */
+		getFullDay: function () {
+			var date = new Date();
+			return this.prefixZero(date.getDate(), 2);
+		},
+
+		/**
+		 * 현재 시간 조회
+		 */
+		getHour: function () {
+			var date = new Date();
+			return date.getFullYear();
+		},
+
+		/**
+		 * 현재 분 조회
+		 */
+		getMinute: function () {
+			var date = new Date();
+			return date.getMinutes() + 1;
+		},
+
+		/**
+		 * 현재 초 조회
+		 */
+		getSeconds: function () {
+			var date = new Date();
+			return date.getSeconds();
+		},
+
+		/**
+		 * 시간 구하기
+		 *
+		 * param 설명
+		 *
+		 * options = {
+		 * 	 addHour(Integer),
+		 *   addMinute(Integer),
+		 *   addSeconds(Integer),
+		 *   separator(String)
+		 * }
+		 */
+		getFullTime: function (options) {
+			if (this.isEmpty(options) == true) {
+				options = {
+					addHour: 0,
+					addMinute: 0,
+					addSeconds: 0,
+					separator: '-'
+				}
+			} else {
+				options.addHour = options.addHour || 0;
+				options.addMinute = options.addMinute || 0;
+				options.addSeconds = options.addSeconds || 0;
+				options.separator = options.separator || ':';
+			}
+
+			var date = new Date();
+			date.setHours(date.getHours() + options.addHour);
+			date.setMinutes(date.getMinutes() + options.addMinute);
+			date.setSeconds(date.getSeconds() + options.addSeconds);
+
+			var h = date.getHours();
+			var m = date.getMinutes();
+			var s = date.getSeconds();
+
+			return this.prefixZero(h, 2) + ":" + this.prefixZero(m, 2) + ":" + this.prefixZero(s, 2);
+		},
+
+		/**
+		 * 시간 구하기
+		 *
+		 * param 설명
+		 *
+		 * options = {
+		 * 	 addHour(Integer),
+		 *   addMinute(Integer),
+		 *   separator(String)
+		 * }
+		 */
+		getTime: function (options) {
+			if (this.isEmpty(options) == true) {
+				options = {
+					addHour: 0,
+					addMinute: 0,
+					separator: '-'
+				}
+			} else {
+				options.addHour = options.addHour || 0;
+				options.addMinute = options.addMinute || 0;
+				options.separator = options.separator || ':';
+			}
+
+			var date = new Date();
+			date.setHours(date.getHours() + options.addHour);
+			date.setMinutes(date.getMinutes() + options.addMinute);
+
+			var h = date.getHours();
+			var m = date.getMinutes();
+
+			return this.prefixZero(h, 2) + ":" + this.prefixZero(m, 2);
+		},
+
+		/**
+		 * 특정 길이만큼 앞에'0' 붙이기
+		 *
+		 * param 설명
+		 *
+		 * text(String or Integer): 맨 뒤에 붙일 문자열(숫자든 문자든 상관웞음)
+		 * length(Integer): 해당 값 만큼 '0'을 붙임 (단, text의 문자열 길이를 뺌)
+		 * ex) this.prefixZero(2, 5) => 00002, this.prefixZero(20, 5) => 00020
+		 *
+		 */
+		prefixZero: function (text, length) {
+			var zero = '';
+			var suffix = text;
+
+			if ((typeof text) === "number") {
+				suffix = text.toString();
+			}
+
+
+			if (suffix.length < length) {
+				for (let i = 0; i < length - suffix.length; i++) {
+					zero += '0';
+				}
+			}
+			return zero + suffix;
+		},
+
+		/**
+		 * Date => text
+		 */
+		dateToText: function (date) {
+			var d = new Date(date);
+			var yyyy = d.getFullYear();
+			var mm = d.getMonth() + 1;
+			var dd = d.getDate();
+			return yyyy + "-" + this.prefixZero(mm, 2) + "-" + this.prefixZero(dd, 2);
+		},
+
+		/**
+		 * 최솟값은 포함, 최댓값은 제외한 정수 난수 생성(최솟값 ~ 최댓값 - 1)
+		 *
+		 * param 설명
+		 *
+		 * min(Integer): 난수 생성시, 최소값
+		 * max(Integer): 난수 생성시, 최대값
+		 *
+		 * ex) getRandomInt(2, 5) => 2~5사이의 정수 난수 값 리턴
+		 */
+		getRandomInt: function (min, max) {
+			min = Math.ceil(min);
+			max = Math.floor(max);
+			return Math.floor(Math.random() * (max - min)) + min;
+		},
+
+		/**
+		 * 현재 시스템의 URL 조회
+		 *
+		 * ex) http://localohst:8080, https://www.naver.com
+		 */
+		getSystemURL: function () {
+			var url = window.location.protocol
+			+ "//" + window.location.host;
+			return url;
+		},
+
+		/**
+		 * 현재 시스템의 URL 경로  조회
+		 *
+		 * ex) http://localohst:8080/dataset/datasetPostList => /dataset/datasetPostList
+		 */
+		getSystemPath: function () {
+			var path = window.location.pathname;
+			return path;
+		},
+
+		/**
+		 * 3글자 마다 콤마 찍기 (돈)
+		 *
+		 * ex) 10000 => 10,000
+		 */
+		comma: function (text) {
+			try {
+				return text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+			} catch (e) {
+				if (this.isEmpty(text) == true) {
+					return "-";
+				} else {
+					return text;
+				}
+			}
+		},
+
+		/**
+		 * 3글자 마다 콤마 찍기 (돈)
+		 *
+		 * ex) 10,000 => 10000
+		 */
+		removeComma: function (text) {
+			try {
+				return text.toString().replace(/,/g, "");;
+			} catch (e) {
+				if (this.isEmpty(text) == true) {
+					return "-";
+				} else {
+					return text;
+				}
+			}
+		},
+
+		/**
+		 * json 데이터 가지고 오기 (외부 JSON 파일 PATH or URL) (동기 요청)
+		 */
+		getJsonByPromise: function (url, isAsync) {
+			if (this.isEmpty(url) == true) {
+				new Error('COMMON_UTIL - getJson(url, isAsync) Error : url(parameter) is empty')
+			}
+			if (this.isEmpty(isAsync) == true) {
+				isAsync = true;
+			}
+
+			return new Promise(function (resolve, reject) {
+				var xhr = new XMLHttpRequest();
+				xhr.onload = function (e) {
+					if (xhr.readyState === 4) {
+						if (xhr.status === 200) {
+							resolve(JSON.parse(this.responseText));
+						} else {
+							reject(this);
+						}
+					}
+				};
+				xhr.onerror = function (e) {
+					reject(this);
+				};
+				xhr.open("GET", url, isAsync);
+				//xhr.responseType='json';
+				xhr.send(null);
+			});
+		},
+
+		/**
+		 * json 데이터 가지고 오기 (동기 요청) (외부 JSON 파일 PATH or URL)
+		 */
+		getJsonBySync: function (url) {
+			var result = {};
+			if (this.isEmpty(url) == true) {
+				new Error('COMMON_UTIL - getJson(url, isAsync) Error : url(parameter) is empty')
+				return result;
+			}
+
+			var xhr = new XMLHttpRequest();
+			xhr.onload = function (e) {
+				if (xhr.readyState === 4) {
+					if (xhr.status === 200) {
+						result = JSON.parse(this.responseText);
+					} else {
+						console.error(this);
+					}
+				}
+			};
+			xhr.onerror = function (e) {
+				console.error(this);
+			};
+			xhr.open("GET", url, false);
+			xhr.send(null);
+
+			return result;
+		},
+
+	}
+
+
+	//초기화
+	function init() {
+        //console.info('commonUtil.js initialized.');
+        return _utils;
+    }
+
+
+	return init();
+
+})();
+
+
+export default CommonUtil;
+
+
+
+
client/views/component/Category.jsx
--- client/views/component/Category.jsx
+++ client/views/component/Category.jsx
@@ -2,11 +2,14 @@
 import Button from "./Button.jsx";
 
 function Menu({ className, children, href, title }) {
+  console.log(`Menu - className : ${className}, children : ${children}`);
+
+
   if (!children) {
     return <li className="venue-lvl">
       <a href={href ?? '#'}>
         <span>{title}</span>      
-        <Button className={"btn-more-small gray-btn margin-left"} btnName={"삭제"} />  
+        <button className={"btn-more-small gray-btn margin-left"} onClick={()=> {}}>삭제</button>
       </a>
     </li>
   }
@@ -18,7 +21,7 @@
   return <li className={className}>
     <a href={href ?? '#'} onClick={() => setOpend(open ? '' : 'open')} className="max-agency">
       <span>{title}</span>
-      <Button className={"btn-more-small red-btn margin-left"} btnName={"추가"} />
+      <button className={"btn-more-small red-btn margin-left"} onClick={()=> {}}>추가</button>
     </a>
     {open && <ul id="venue-scope-options">
       {children}
client/views/component/Modal_Guardian.jsx
--- client/views/component/Modal_Guardian.jsx
+++ client/views/component/Modal_Guardian.jsx
@@ -5,372 +5,80 @@
 import Pagination from "./Pagination.jsx";
 
 
-export default function Modal_Guardian({ open, close, header, useSeniorId }) {
-
-  const seniorId = useSeniorId;
-  //대상자 - 보호자 매칭 리스트 
-  const [sgMatchList, setSgMatchList] = React.useState([]);
-  const [guardianList, setGuardianList] = React.useState([]);
-  const [addGuardian, setAddGuardian] = React.useState(true); //추가된 보호자가 있는지 확인
-
-  //사용자 등록 초기값 설정
-  const [userName, setUserName] = React.useState("");
-  const [gender, setGender] = React.useState("");
-  const [brith, setBrith] = React.useState("");
-  const [telNum, setTelNum] = React.useState("");
-  const [homeAddress, setHomeAddress] = React.useState("");
-  const [relationship, setRelationship] = React.useState("");
-  const [guardianId, setGuardianId] = React.useState("");
-
-  //-------- 페이징 작업 설정 시작 --------//
-  const limit = 5; // 페이지당 보여줄 공지 개수
-  const [page, setPage] = React.useState(1); //page index
-  const offset = (page - 1) * limit; //게시물 위치 계산
-  const [guardianTotal, setGuardianTotal] = React.useState(0); //최대길이 넣을 변수
-
-  //-------- 변경되는 데이터 Handler 설정 --------//
-  const handleUserName = (e) => {
-    e.target.value = e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, '');
-    setUserName(e.target.value);
-  };
-  const handleBrithday = (e) => {
-    setBrith(e.target.value);
-  };
-  const handleTelNum = (e) => {
-    e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`);
-    setTelNum(e.target.value);
-  };
-  const handelRelationship = (e) => {
-    setRelationship(e.target.value);
-  };
-  const handleGuarianId = (e) => {
-    setGuardianId(e.target.value);
-  };
-
-  // 데이터 초기화 함수
-  const dataReset = () => {
-    setGuardianId("");
-    setUserName("");
-    setBrith("");
-    setTelNum("");
-    setRelationship("");
-  }
-  // 매칭 리스트 출력 영역
-  const getSelectMatchList = () => {
-    fetch("/user/selectSeniorGuardianMatch.json", {
-      method: "POST",
-      headers: {
-        'Content-Type': 'application/json; charset=UTF-8'
-      },
-      body: JSON.stringify({
-        senior_id: seniorId,
-        viewPage : "matchView",
-      }),
-    }).then((response) => response.json()).then((data) => {
-      console.log("getSelectMatchList : ", data);
-      setSgMatchList(data);
-      setGuardianTotal(data.length);
-      setAddGuardian(false);
-    }).catch((error) => {
-      console.log('getSelectMatchList() /user/selectSeniorGuardianMatch.json error : ', error);
-    });
-  };
-
-  // 보호자 리스트 불러오기
-  const getSelectGuardianList = () => {
-    fetch("/user/selectUserList.json", {
-      method: "POST",
-      headers: {
-        'Content-Type': 'application/json; charset=UTF-8'
-      },
-      body: JSON.stringify({
-        agency_id: 'AGENCY01',
-        authority: 'GUARDIAN01',
-      }),
-    }).then((response) => response.json()).then((data) => {
-      const rowData = data;
-      setGuardianList(rowData)
-
-    }).catch((error) => {
-      console.log('getSelectSeniorList() /user/selectUserList.json error : ', error);
-    });
-  };
-
-  // 보호자 등록 영역
-  const insertUser = () => {
-    if (userName == "") {
-      alert("이름을 입력해 주세요.");
-      return;
-    } else if (brith == "") {
-      alert("생년월일을 선택해 주세요.");
-      return;
-    } else if (telNum == "") {
-      alert("연락처를 입력해 선택해 주세요.");
-      return;
-    }
-    var insertBtn = confirm("등록하시겠습니까?");
-    if (insertBtn) {
-      fetch("/user/insertUserData.json", {
-        method: "POST",
-        headers: {
-          'Content-Type': 'application/json; charset=UTF-8'
-        },
-        body: JSON.stringify({
-          user_name: userName,
-          user_gender: gender != "" ? gender : null,
-          user_birth: brith,
-          user_phonenumber: telNum,
-          user_address: homeAddress != "" ? homeAddress : null,
-          agency_id: 'AGENCY01',
-          government_id: 'GOVERNMENT01',
-          authority: 'GUARDIAN01',
-
-        }),
-      }).then((response) => response.json()).then((data) => {
-        console.log("보호자 등록");
-        insertGuadian();
-      }).catch((error) => {
-        console.log('insertUser() /user/insertUserData.json error : ', error);
-      });
-    } else {
-      return;
-    }
-  }
-  const insertGuadian = () => {
-    fetch("/user/insertGuardian.json", {
-      method: "POST",
-      headers: {
-        'Content-Type': 'application/json; charset=UTF-8'
-      },
-      body: JSON.stringify({
-        user_phonenumber: telNum,
-      }),
-    }).then((response) => response.json()).then((data) => {
-      console.log("보호자 테이블 데이터 등록");
-      matchSeniorGuadian2();
-    }).catch((error) => {
-      console.log('insertGuadian() /user/insertGuardian.json error : ', error);
-    });
-  };
-
-  const matchSeniorGuadian = () => {
-    fetch("/user/insertSeniorGuardianMatch.json", {
-      method: "POST",
-      headers: {
-        'Content-Type': 'application/json; charset=UTF-8'
-      },
-      body: JSON.stringify({
-        senior_id: seniorId,
-        guardian_id: guardianId,
-        senior_relationship: relationship,
-      }),
-    }).then((response) => response.json()).then((data) => {
-      console.log("매칭 등록");
-      dataReset();
-      setAddGuardian(true);
-    }).catch((error) => {
-      console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error);
-    });
-  };
-
-  const matchSeniorGuadian2 = () => {
-    fetch("/user/insertSeniorGuardianMatch.json", {
-      method: "POST",
-      headers: {
-        'Content-Type': 'application/json; charset=UTF-8'
-      },
-      body: JSON.stringify({
-        senior_id: seniorId,
-        user_phonenumber: telNum,
-        senior_relationship: relationship,
-      }),
-    }).then((response) => response.json()).then((data) => {
-      console.log("매칭 등록");
-      dataReset();
-      setAddGuardian(true);
-    }).catch((error) => {
-      console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error);
-    });
-  };
-
-  // 시니어 보호자 매칭 제거
-	const updateSeniorGuardianMatch = (guardian_id) => {
-    let insertBtn = confirm("삭제하시겠습니까?");
-    if (insertBtn) {
-      fetch("/user/updateGuardianMatchEnd.json", {
-        method: "POST",
-        headers: {
-          'Content-Type': 'application/json; charset=UTF-8'
-        },
-        body: JSON.stringify({
-          senior_id: seniorId,
-          guardian_id: guardian_id,
-          endMatch: "matchDel",
-        }),
-      }).then((response) => response.json()).then((data) => {
-        alert('삭제되었습니다.');
-        setAddGuardian(true);
-        }).catch((error) => {
-        console.log('updateSeniorGuardianMatch() /user/updateGuardianMatchEnd.json error : ', error);
-      });
-    } else {
-      return;
-    }
-	}
-
-  // 보호자 등록페이지 데이터
-  const thead = [
-    "No",
-    "이름",
-    "생년월일",
-    "연락처",
-    "대상자와의 관계",
-    "삭제"
-  ];
-  const key = [
-    "rn",
-    "guardian_name",
-    "user_birth",
-    "user_phonenumber",
-    "senior_relationship",
-  ];
-
-  React.useEffect(() => {
-    getSelectGuardianList();
-    getSelectMatchList();
-  }, [addGuardian])
+export default function Modal_Guardian({ open, close, seniorId }) {
 
   return (
     <div class={open ? "openModal modal" : "modal"}>
       {open ? (
         <div className="modal-inner">
           <div className="modal-header flex">
-            {header}
-            <Button className={"close"} onClick={close} btnName={"X"} />
+            보호자(가족) 보기
+            <button className={"close"} onClick={() => {close()}}>X</button>
           </div>
           <div className="modal-main">
             <div className="board-wrap">
-              <SubTitle explanation={"이미 등록된 사용자는 기존 ID,PW를 사용하시면 됩니다."} className="margin-bottom" />
-              <table className="margin-bottom2 senior-insert">
-                <tr>
-                  <th>검색</th>
-                  <input type="text" list="protectorlist" value={guardianId} onChange={handleGuarianId} />
-                  <datalist id="protectorlist">
-                    {/* <option value="가족1(ID)"></option>
-                    <option value="가족2(ID)"></option> */}
-                    {guardianList.map((item) => {
-                      // console.log('item : ',item)
-                      // setGaudianId(item['user_id'])
-                      // setTelNum(item['user_phonenumber'])
-                      return <option value={item['user_id']}>{item['user_name']}({item['user_id']})</option>
-                    })}
-                  </datalist>
-                </tr>
-                <tr>
-                  <th>대상자와의 관계</th>
-                  <td colSpan={3}>
-                    <input type="text" value={relationship} onChange={handelRelationship} />
-                  </td>
-                </tr>
-              </table>
-              <div className="btn-wrap flex-center margin-bottom5">
-                <Button
-                  className={"btn-small green-btn"}
-                  btnName={"등록"}
-                  onClick={() => {
-                    matchSeniorGuadian();
-                  }}
-                />
+
+              <SubTitle explanation={"OOO님의 보호자(가족)"} className="margin-bottom" />
+              <div>
+                <table className='caregiver-user'>
+                  <thead>
+                    <tr>
+                      <th>No</th>
+                      <th>이름</th>
+                      <th>대상자와의 관계</th>
+                      <th>연락처</th>
+                      <th>생년월일</th>
+                      <th>삭제</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                    <tr>
+                      <td>No</td>
+                      <td>이름</td>
+                      <td>대상자와의 관계</td>
+                      <td>연락처</td>
+                      <td>생년월일</td>
+                      <td><button className={"btn-small gray-btn"} onClick={() => {}}>삭제</button></td>
+                    </tr>
+                  </tbody>
+                </table>
               </div>
+              <div>
+                {/* <Pagination total={guardianTotal} limit={limit} page={page} setPage={setPage} /> */}
+              </div>
+
+
               <SubTitle explanation={"최초 ID는 연락처, PW는 생년월일 8자리입니다."} className="margin-bottom" />
               <table className="margin-bottom2 senior-insert">
                 <tr>
                   <th><span style={{color : "red"}}>*</span>이름</th>
                   <td>
-                    <input type="text" value={userName} onChange={handleUserName} />
+                    <input type="text"/>
                   </td>
                   <th><span style={{color : "red"}}>*</span>생년월일</th>
                   <td>
                     <div className="flex">
-                      <input type='date' value={brith} onChange={handleBrithday} />
+                      <input type='date' />
                     </div>
                   </td>
                 </tr>
                 <tr>
                   <th><span style={{color : "red"}}>*</span>연락처</th>
                   <td colSpan={3}>
-                    <input type="input" maxLength="13" value={telNum} onChange={handleTelNum} />
+                    <input type="input" maxLength="13" />
                   </td>
                 </tr>
                 <tr>
                   <th>대상자와의 관계</th>
                   <td colSpan={3}>
-                    <input type="text" value={relationship} onChange={handelRelationship} />
+                    <input type="text" />
                   </td>
                 </tr>
               </table>
               <div className="btn-wrap flex-center margin-bottom5">
-                <Button
-                  className={"btn-small green-btn"}
-                  btnName={"추가"}
-                  onClick={() => {
-                    insertUser()
-                  }}
-                />
+                <button className={"btn-small green-btn"} onClick={() => {}}>추가</button>
               </div>
-              <div>
-                {/* <Table
-                  className={"caregiver-user"}
-                  head={thead3}
-                  contents={sgMatchList}
-                  contentKey={key3}
-                  view={"guadianMatch"}
-                  offset={offset}
-                  limit={limit}
-                /> */}
-                <table className='caregiver-user'>
-                  <thead>
-                    <tr>
-                      {thead.map((i) => {
-                        return <th>{i}</th>;
-                      })}
-                    </tr>
-                  </thead>
-                  <tbody>
-                    {sgMatchList.slice(offset, offset + limit).map((i, index) => {
-                      const guardian_id = i.guardian_id;
-                      return (
-                        <tr key={index}>
-                          {key.map((kes) => {
-                            return (
-                              <>
-                                <td
-                                onClick={() => {
-                                    console.log("i.guardian_id : ", i.guardian_id);
-                                  }}>
-                                  {i[kes]}
-                                </td>
-                              </>
-                            );
-                          })}
-                          <td>
-                            <Button
-                              className={"btn-small gray-btn"}
-                              btnName={"삭제"}
-                              onClick={() => {
-                                updateSeniorGuardianMatch(guardian_id);
-                              }}
-                            />
-                          </td>
-                        </tr>
-                      );
-                    })}
-                  </tbody>
-                </table>
-              </div>
-              <div>
-                <Pagination total={guardianTotal} limit={limit} page={page} setPage={setPage} />
-              </div>
+
             </div>
           </div>
         </div>
 
client/views/component/Modal_Guardian_back_230329.jsx (added)
+++ client/views/component/Modal_Guardian_back_230329.jsx
@@ -0,0 +1,381 @@
+import React from "react";
+import Button from "./Button.jsx";
+import SubTitle from "./SubTitle.jsx";
+import Table from "./Table.jsx";
+import Pagination from "./Pagination.jsx";
+
+
+export default function Modal_Guardian({ open, close, header, useSeniorId }) {
+
+  const seniorId = useSeniorId;
+  //대상자 - 보호자 매칭 리스트 
+  const [sgMatchList, setSgMatchList] = React.useState([]);
+  const [guardianList, setGuardianList] = React.useState([]);
+  const [addGuardian, setAddGuardian] = React.useState(true); //추가된 보호자가 있는지 확인
+
+  //사용자 등록 초기값 설정
+  const [userName, setUserName] = React.useState("");
+  const [gender, setGender] = React.useState("");
+  const [brith, setBrith] = React.useState("");
+  const [telNum, setTelNum] = React.useState("");
+  const [homeAddress, setHomeAddress] = React.useState("");
+  const [relationship, setRelationship] = React.useState("");
+  const [guardianId, setGuardianId] = React.useState("");
+
+  //-------- 페이징 작업 설정 시작 --------//
+  const limit = 5; // 페이지당 보여줄 공지 개수
+  const [page, setPage] = React.useState(1); //page index
+  const offset = (page - 1) * limit; //게시물 위치 계산
+  const [guardianTotal, setGuardianTotal] = React.useState(0); //최대길이 넣을 변수
+
+  //-------- 변경되는 데이터 Handler 설정 --------//
+  const handleUserName = (e) => {
+    e.target.value = e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, '');
+    setUserName(e.target.value);
+  };
+  const handleBrithday = (e) => {
+    setBrith(e.target.value);
+  };
+  const handleTelNum = (e) => {
+    e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`);
+    setTelNum(e.target.value);
+  };
+  const handelRelationship = (e) => {
+    setRelationship(e.target.value);
+  };
+  const handleGuarianId = (e) => {
+    setGuardianId(e.target.value);
+  };
+
+  // 데이터 초기화 함수
+  const dataReset = () => {
+    setGuardianId("");
+    setUserName("");
+    setBrith("");
+    setTelNum("");
+    setRelationship("");
+  }
+  // 매칭 리스트 출력 영역
+  const getSelectMatchList = () => {
+    fetch("/user/selectSeniorGuardianMatch.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({
+        senior_id: seniorId,
+        viewPage : "matchView",
+      }),
+    }).then((response) => response.json()).then((data) => {
+      console.log("getSelectMatchList : ", data);
+      setSgMatchList(data);
+      setGuardianTotal(data.length);
+      setAddGuardian(false);
+    }).catch((error) => {
+      console.log('getSelectMatchList() /user/selectSeniorGuardianMatch.json error : ', error);
+    });
+  };
+
+  // 보호자 리스트 불러오기
+  const getSelectGuardianList = () => {
+    fetch("/user/selectUserList.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({
+        agency_id: 'AGENCY01',
+        authority: 'GUARDIAN01',
+      }),
+    }).then((response) => response.json()).then((data) => {
+      const rowData = data;
+      setGuardianList(rowData)
+
+    }).catch((error) => {
+      console.log('getSelectSeniorList() /user/selectUserList.json error : ', error);
+    });
+  };
+
+  // 보호자 등록 영역
+  const insertUser = () => {
+    if (userName == "") {
+      alert("이름을 입력해 주세요.");
+      return;
+    } else if (brith == "") {
+      alert("생년월일을 선택해 주세요.");
+      return;
+    } else if (telNum == "") {
+      alert("연락처를 입력해 선택해 주세요.");
+      return;
+    }
+    var insertBtn = confirm("등록하시겠습니까?");
+    if (insertBtn) {
+      fetch("/user/insertUserData.json", {
+        method: "POST",
+        headers: {
+          'Content-Type': 'application/json; charset=UTF-8'
+        },
+        body: JSON.stringify({
+          user_name: userName,
+          user_gender: gender != "" ? gender : null,
+          user_birth: brith,
+          user_phonenumber: telNum,
+          user_address: homeAddress != "" ? homeAddress : null,
+          agency_id: 'AGENCY01',
+          government_id: 'GOVERNMENT01',
+          authority: 'GUARDIAN01',
+
+        }),
+      }).then((response) => response.json()).then((data) => {
+        console.log("보호자 등록");
+        insertGuadian();
+      }).catch((error) => {
+        console.log('insertUser() /user/insertUserData.json error : ', error);
+      });
+    } else {
+      return;
+    }
+  }
+  const insertGuadian = () => {
+    fetch("/user/insertGuardian.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({
+        user_phonenumber: telNum,
+      }),
+    }).then((response) => response.json()).then((data) => {
+      console.log("보호자 테이블 데이터 등록");
+      matchSeniorGuadian2();
+    }).catch((error) => {
+      console.log('insertGuadian() /user/insertGuardian.json error : ', error);
+    });
+  };
+
+  const matchSeniorGuadian = () => {
+    fetch("/user/insertSeniorGuardianMatch.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({
+        senior_id: seniorId,
+        guardian_id: guardianId,
+        senior_relationship: relationship,
+      }),
+    }).then((response) => response.json()).then((data) => {
+      console.log("매칭 등록");
+      dataReset();
+      setAddGuardian(true);
+    }).catch((error) => {
+      console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error);
+    });
+  };
+
+  const matchSeniorGuadian2 = () => {
+    fetch("/user/insertSeniorGuardianMatch.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({
+        senior_id: seniorId,
+        user_phonenumber: telNum,
+        senior_relationship: relationship,
+      }),
+    }).then((response) => response.json()).then((data) => {
+      console.log("매칭 등록");
+      dataReset();
+      setAddGuardian(true);
+    }).catch((error) => {
+      console.log('matchSeniorGuadian() /user/insertSeniorGuardianMatch.json error : ', error);
+    });
+  };
+
+  // 시니어 보호자 매칭 제거
+	const updateSeniorGuardianMatch = (guardian_id) => {
+    let insertBtn = confirm("삭제하시겠습니까?");
+    if (insertBtn) {
+      fetch("/user/updateGuardianMatchEnd.json", {
+        method: "POST",
+        headers: {
+          'Content-Type': 'application/json; charset=UTF-8'
+        },
+        body: JSON.stringify({
+          senior_id: seniorId,
+          guardian_id: guardian_id,
+          endMatch: "matchDel",
+        }),
+      }).then((response) => response.json()).then((data) => {
+        alert('삭제되었습니다.');
+        setAddGuardian(true);
+        }).catch((error) => {
+        console.log('updateSeniorGuardianMatch() /user/updateGuardianMatchEnd.json error : ', error);
+      });
+    } else {
+      return;
+    }
+	}
+
+  // 보호자 등록페이지 데이터
+  const thead = [
+    "No",
+    "이름",
+    "생년월일",
+    "연락처",
+    "대상자와의 관계",
+    "삭제"
+  ];
+  const key = [
+    "rn",
+    "guardian_name",
+    "user_birth",
+    "user_phonenumber",
+    "senior_relationship",
+  ];
+
+  React.useEffect(() => {
+    getSelectGuardianList();
+    getSelectMatchList();
+  }, [addGuardian])
+
+  return (
+    <div class={open ? "openModal modal" : "modal"}>
+      {open ? (
+        <div className="modal-inner">
+          <div className="modal-header flex">
+            {header}
+            <Button className={"close"} onClick={close} btnName={"X"} />
+          </div>
+          <div className="modal-main">
+            <div className="board-wrap">
+              <SubTitle explanation={"이미 등록된 사용자는 기존 ID,PW를 사용하시면 됩니다."} className="margin-bottom" />
+              <table className="margin-bottom2 senior-insert">
+                <tr>
+                  <th>검색</th>
+                  <input type="text" list="protectorlist" value={guardianId} onChange={handleGuarianId} />
+                  <datalist id="protectorlist">
+                    {/* <option value="가족1(ID)"></option>
+                    <option value="가족2(ID)"></option> */}
+                    {guardianList.map((item) => {
+                      // console.log('item : ',item)
+                      // setGaudianId(item['user_id'])
+                      // setTelNum(item['user_phonenumber'])
+                      return <option value={item['user_id']}>{item['user_name']}({item['user_id']})</option>
+                    })}
+                  </datalist>
+                </tr>
+                <tr>
+                  <th>대상자와의 관계</th>
+                  <td colSpan={3}>
+                    <input type="text" value={relationship} onChange={handelRelationship} />
+                  </td>
+                </tr>
+              </table>
+              <div className="btn-wrap flex-center margin-bottom5">
+                <Button
+                  className={"btn-small green-btn"}
+                  btnName={"등록"}
+                  onClick={() => {
+                    matchSeniorGuadian();
+                  }}
+                />
+              </div>
+              <SubTitle explanation={"최초 ID는 연락처, PW는 생년월일 8자리입니다."} className="margin-bottom" />
+              <table className="margin-bottom2 senior-insert">
+                <tr>
+                  <th><span style={{color : "red"}}>*</span>이름</th>
+                  <td>
+                    <input type="text" value={userName} onChange={handleUserName} />
+                  </td>
+                  <th><span style={{color : "red"}}>*</span>생년월일</th>
+                  <td>
+                    <div className="flex">
+                      <input type='date' value={brith} onChange={handleBrithday} />
+                    </div>
+                  </td>
+                </tr>
+                <tr>
+                  <th><span style={{color : "red"}}>*</span>연락처</th>
+                  <td colSpan={3}>
+                    <input type="input" maxLength="13" value={telNum} onChange={handleTelNum} />
+                  </td>
+                </tr>
+                <tr>
+                  <th>대상자와의 관계</th>
+                  <td colSpan={3}>
+                    <input type="text" value={relationship} onChange={handelRelationship} />
+                  </td>
+                </tr>
+              </table>
+              <div className="btn-wrap flex-center margin-bottom5">
+                <Button
+                  className={"btn-small green-btn"}
+                  btnName={"추가"}
+                  onClick={() => {
+                    insertUser()
+                  }}
+                />
+              </div>
+              <div>
+                {/* <Table
+                  className={"caregiver-user"}
+                  head={thead3}
+                  contents={sgMatchList}
+                  contentKey={key3}
+                  view={"guadianMatch"}
+                  offset={offset}
+                  limit={limit}
+                /> */}
+                <table className='caregiver-user'>
+                  <thead>
+                    <tr>
+                      {thead.map((i) => {
+                        return <th>{i}</th>;
+                      })}
+                    </tr>
+                  </thead>
+                  <tbody>
+                    {sgMatchList.slice(offset, offset + limit).map((i, index) => {
+                      const guardian_id = i.guardian_id;
+                      return (
+                        <tr key={index}>
+                          {key.map((kes) => {
+                            return (
+                              <>
+                                <td
+                                onClick={() => {
+                                    console.log("i.guardian_id : ", i.guardian_id);
+                                  }}>
+                                  {i[kes]}
+                                </td>
+                              </>
+                            );
+                          })}
+                          <td>
+                            <Button
+                              className={"btn-small gray-btn"}
+                              btnName={"삭제"}
+                              onClick={() => {
+                                updateSeniorGuardianMatch(guardian_id);
+                              }}
+                            />
+                          </td>
+                        </tr>
+                      );
+                    })}
+                  </tbody>
+                </table>
+              </div>
+              <div>
+                <Pagination total={guardianTotal} limit={limit} page={page} setPage={setPage} />
+              </div>
+            </div>
+          </div>
+        </div>
+      ) : null}
+    </div>
+
+  );
+}(파일 끝에 줄바꿈 문자 없음)
client/views/component/Modal_SeniorInsert.jsx
--- client/views/component/Modal_SeniorInsert.jsx
+++ client/views/component/Modal_SeniorInsert.jsx
@@ -1,268 +1,357 @@
-import React from "react";
+import React, { useState, useRef } from "react";
+import { useSelector } from "react-redux";
 import Button from "./Button.jsx";
 import SubTitle from "./SubTitle.jsx";
 
-export default function Modal({ open, close, header, setModalOpen3, setAddSenior }) {
-   // 사용자 등록 시 초기값 세팅
-  //  const [seniorId, setSeniorId] = React.useState("");
-   const [userName, setUserName] = React.useState("");
-   const [gender, setGender] = React.useState("");
-   const [brith, setBrith] = React.useState("");
-   const [telNum, setTelNum] = React.useState("");
-   const [homeAddress, setHomeAddress] = React.useState("");
-   const [medicineM, setMedicineM] = React.useState(false);
-   const [medicineL, setMedicineL] = React.useState(false);
-   const [medicineD, setMedicineD] = React.useState(false);
-   const [medication, setMedication] = React.useState("");
-   const [note, setNote] = React.useState("");
+import CommonUtil from "../../resources/js/CommonUtil.js";
 
-  // //id blor 처리 진행 
-  // const inputRef = React.useRef();
-  // const settingBlor = (e) => {
-  //   inputRef.current.blur();
-  // }
+export default function Modal({ open, close, seniorInsertCallback, defaultAgencyId, defaultGovernmentId }) {
 
-     // 등록 후 초기화 진행
-  const dataReset = () => {
-    // setSeniorId("");
-    setUserName("");
-    setGender("");
-    setBrith("");
-    setTelNum("");
-    setHomeAddress("");
-    setMedicineM("");
-    setMedicineL("");
-    setMedicineD("");
-    setMedication("");
-    setNote("");
-  }
-   //-------- 변경되는 데이터 Handler 설정 --------//
-  // const handleUserId = (e) => {
-  //   console.log(e.target.value);
-  //   setSeniorId(e.target.value);
-  // };
-  const handleUserName = (e) => {
-    e.target.value=e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, '');
-    setUserName(e.target.value);
-  };
-  const handleGender = (e) => {
-    setGender(e.target.value);
-  };
-  const handleBrithday = (e) => {
-    setBrith(e.target.value);
-  };
-  const handleTelNum = (e) => {
-    e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`);
-    setTelNum(e.target.value);
-  };
-  const handleHomeAddress = (e) => {
-    setHomeAddress(e.target.value);
-  };
-  const handleMedicineM = (e) => {
-    setMedicineM(e.target.checked);
-  };
-  const handleMedicineL = (e) => {
-    setMedicineL(e.target.checked);
-  };
-  const handleMedicineD = (e) => {
-    setMedicineD(e.target.checked);
-  };
-  const handleMedication = (e) => {
-    setMedication(e.target.value);
-  };
-  const handleNote = (e) => {
-    setNote(e.target.value);
-  };
+  //console.log(`seniorInsertModal - defaultGovernmentId:${defaultGovernmentId}, defaultAgencyId:${defaultAgencyId}`)
 
-  //-------- 등록 버튼 동작 수행 영역 시작 --------//
-  // 대상자 정보 등록을 위한 함수 
-  const InsertUserData = () => {
-    //-------- 유효성 체크 --------//
-    if(userName == ""){
-      alert("이름을 입력해 주세요.");
-      return ;
-    } else if(gender == "") {
-      alert("성별을 선택해 주세요.");
-      return ;
-    } else if(brith == "") {
-      alert("생년월일을 선택해 주세요.");
-      return ;
-    } else if(telNum == "") {
-      alert("연락처를 입력해 선택해 주세요.");
-      return ;
-    } else if(homeAddress == "") {
-      alert("주소를 선택해 주세요.");
-      return ;
-    }
-    var insertBtn = confirm("등록하시겠습니까?");
-    if (insertBtn) {
-      fetch("/user/insertUserData.json", {
-        method: "POST",
-        headers: {
-          'Content-Type': 'application/json; charset=UTF-8'
-        },
-        body: JSON.stringify({
-          user_name: userName,
-          user_gender: gender,
-          user_birth: brith,
-          user_phonenumber: telNum,
-          user_address: homeAddress,
-          agency_id: 'AGENCY01',
-          government_id: 'GOVERNMENT01',
-          authority: 'SENIOR01',
-        }),
-      }).then((response) => response.json()).then((data) => {
-        console.log("대상자 정보 등록");
-        InsertUserPillData();
-      }).catch((error) => {
-        console.log('insertUserData() /user/insertUserData.json error : ', error);
-      });
-    } else {
-      return;
-    }
-  };
-  // 대상자 약 복용 정보 등록을 위한 함수 
-  const InsertUserPillData = () => {
-    fetch("/user/insertSeniorMadication.json", {
+  /**** 기본 조회 데이터 (시작) ****/
+  //전역 변수 저장 객체
+  const state = useSelector((state) => {return state});
+
+  //기관 계층 구조 목록
+  const [orgListOfHierarchy, setOrgListOfHierarchy] = React.useState([]);
+  //기관(관리, 시행) 계층 구조 목록 조회
+  const orgSelectListOfHierarchy = () => {
+    fetch("/org/orgSelectListOfHierarchy.json", {
       method: "POST",
       headers: {
         'Content-Type': 'application/json; charset=UTF-8'
       },
-      body: JSON.stringify({
-        user_phonenumber: telNum,
-        breakfast_medication_check: medicineM,
-        lunch_medication_check: medicineL,
-        dinner_medication_check: medicineD,
-        medication_pill: medication,
-        senior_note: note,
-      }),
+      body: JSON.stringify({}),
     }).then((response) => response.json()).then((data) => {
-      console.log("약 정보 등록");
-      dataReset();
-      setAddSenior(true)
-      alert("등록 되었습니다.");
-      noticeModalClose()
-
+      console.log("기관(관리, 시행) 계층 구조 목록 조회 : ", data);
+      setOrgListOfHierarchy(data);
     }).catch((error) => {
-      console.log('InsertUserPillData() /user/insertSeniorMadication.json error : ', error);
+      console.log('orgSelectListOfHierarchy() /org/orgSelectListOfHierarchy.json error : ', error);
     });
   };
-  //-------- 등록 버튼 동작 수행 영역 끝 --------/
-  //-------- 모달 종료 -------->
-  const noticeModalClose = () => {
-    dataReset();
-    setModalOpen3(false);
-  };
+  const getAgencyList = () => {
+    const government = orgListOfHierarchy.find(item => item['government_id'] == senior['government_id']);
+    if (CommonUtil.isEmpty(government) || CommonUtil.isEmpty(government['agencyList'])) {
+      return [];
+    } else {
+      return government['agencyList'];
+    }
+  }
+
+  const [medicationTimeCodeList, setMedicationTimeCodeList] = React.useState([]);
+  //복약 시간 코드 목록 조회
+  const medicationTimeCodeSelectList = () => {
+    fetch("/common/medicationTimeCodeSelectList.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({}),
+    }).then((response) => response.json()).then((data) => {
+      console.log("복약 시간 코드 목록 조회 : ", data);
+      setMedicationTimeCodeList(data);
+
+      //시니어 복약 정보 미리 세팅
+      let newSenior = JSON.parse(JSON.stringify(senior));
+      for (let i = 0; i < data.length; i++) {
+        newSenior['seniorMedicationList'].push(data[i]['medication_time_code']);
+      }
+      setSenior(newSenior);
+    }).catch((error) => {
+      console.log('medicationTimeCodeSelectList() /common/medicationTimeCodeSelectList.json error : ', error);
+    });
+  }
+  /**** 기본 조회 데이터 (종료) ****/
+
+
+
+
+  //등록할 시니어 정보
+  const [senior, setSenior] = useState({
+    'user_id': null,
+    'user_name': null,
+    'user_password': null,
+    'user_phonenumber': null,
+    'user_birth': null,
+    'user_gender': null,
+    'user_address': null,
+    'user_email': null,
+    'authority': 'ROLE_SENIOR',
+    'agency_id': !defaultAgencyId ? state.loginUser['agency_id'] : defaultAgencyId,
+    'government_id': !defaultGovernmentId ? state.loginUser['government_id'] : defaultGovernmentId,
+
+    'senior_id': null,
+    'care_grade': null,
+    'medication_pill': null,
+    'underlie_disease': null,
+    'senior_note': null,
+
+    'seniorMedicationList': [],
+  });
+  //console.log(`seniorInsertModal - senior:`, senior);
+
+  //각 데이터별로 Dom 정보 담을 Ref 생성
+  const seniorRefInit = JSON.parse(JSON.stringify(senior));
+  seniorRefInit['user_gender'] = {};
+  const seniorRef = useRef(seniorRefInit);
+
+  //등록할 시니어 정보 변경
+  const seniorValueChange = (targetKey, value) => {
+    let newSenior = JSON.parse(JSON.stringify(senior));
+    newSenior[targetKey] = value;
+    setSenior(newSenior);
+  }
+  //등록할 시니어의 관리기관 변경
+  const seniorGovernmentIdChange = (value) => {
+    let newSenior = JSON.parse(JSON.stringify(senior));
+    if (CommonUtil.isEmpty(value) == true) {
+      newSenior['government_id'] = null;
+    } else {
+      newSenior['government_id'] = value;
+    }
+    newSenior['agency_id'] = null;
+    setSenior(newSenior);
+  }
+  //등록할 시니어의 시행기관 변경
+  const seniorAgencyIdChange = (value) => {
+    let newSenior = JSON.parse(JSON.stringify(senior));
+    if (CommonUtil.isEmpty(value) == true) {
+      newSenior['agency_id'] = null;
+    } else {
+      newSenior['agency_id'] = value;
+    }
+    setSenior(newSenior);
+  }
+  //등록할 시니어의 기본 복약 정보 변경
+  const seniorMedicationChange = (value, isChecked) => {
+    let newSenior = JSON.parse(JSON.stringify(senior));
+    let index = newSenior['seniorMedicationList'].indexOf(value);
+    if (isChecked == true && index == -1) {
+      newSenior['seniorMedicationList'].push(value);
+      setSenior(newSenior);
+    } else if (isChecked == false && index > -1) {
+      newSenior['seniorMedicationList'].splice(index, 1);
+      setSenior(newSenior);
+    } else {
+      return;
+    }
+  }
+
+
+  //시니어 등록 유효성 검사
+  const seniorInsertValidation = () => {
+    if (CommonUtil.isEmpty(senior['user_name']) == true) {
+      seniorRef.current['user_name'].focus();
+      alert("이름을 입력해 주세요.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(senior['user_gender']) == true) {
+      seniorRef.current['user_gender']['m'].focus();
+      alert("성별을 선택해 주세요.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(senior['user_birth']) == true) {
+      seniorRef.current['user_birth'].focus();
+      alert("생년월일을 선택해 주세요.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(senior['user_phonenumber']) == true) {
+      seniorRef.current['user_phonenumber'].focus();
+      alert("연락처를 입력해 주세요.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(senior['user_address']) == true) {
+      seniorRef.current['user_address'].focus();
+      alert("주소를 입력해 주세요.");
+      return false;
+    }
+
+    return true;
+  }
+  //시니어 등록
+  const seniorInsert = () => {
+    if (seniorInsertValidation() == false) {
+      return;
+    }
+
+    fetch("/user/seniorInsert.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(senior),
+    }).then((response) => response.json()).then((data) => {
+      console.log("시니어 등록 결과(건수) : ", data);
+      if (data > 0) {
+        alert("등록완료");
+        seniorInsertCallback();
+      } else {
+        alert("등록에 실패하였습니다. 관리자에게 문의바랍니다.");
+      }
+    }).catch((error) => {
+      console.log('seniorInsert() /user/seniorInsert.json error : ', error);
+    });
+  }
+
+
+
+  //Mounted
+  React.useEffect(() => {
+    orgSelectListOfHierarchy();
+    medicationTimeCodeSelectList();
+  }, []);
+
+  //Mounted
+  React.useEffect(() => {
+    const government_id = !defaultGovernmentId ? state.loginUser['government_id'] : defaultGovernmentId;
+    const agency_id = !defaultAgencyId ? state.loginUser['agency_id'] : defaultAgencyId;
+
+    let newSenior = JSON.parse(JSON.stringify(senior));
+    newSenior['government_id'] = government_id;
+    newSenior['agency_id'] = agency_id;
+    setSenior(newSenior);
+  }, [defaultGovernmentId, defaultAgencyId]);
+
+
+
   return (
     <div class={open ? "openModal modal" : "modal"}>
       {open ? (
         <div className="modal-inner">
           <div className="modal-header flex">
-            {header}
-            <Button className={"close"} onClick={noticeModalClose} btnName={"X"} />
+            대상자(시니어) 등록
+            <button className={"close"} onClick={() => {close()}}>X</button>
           </div>
           <div className="modal-main">
-          <div className="board-wrap">
-          <SubTitle explanation={"회원 등록 시 ID는 연락처, 패스워드는 생년월일 8자리입니다."} className="margin-bottom" />
-          <table className="margin-bottom2 senior-insert">
-            {/* <tr>
-              <th>대상자등록번호</th>
-              <td colSpan={3} className="flex">
-                <input type="text" placeholder="생성하기 버튼 클릭 시 자동으로 생성됩니다."/>
-                <Button
-              className={"btn-large gray-btn"}
-              btnName={"생성하기"}
-            />
-              </td>
-            </tr> */}
-            {/* <tr>
-              <th>아이디</th>
-              <td>
-                <input type="text" value={`${telNum}_${userName}`.replace(/[-]/g,'')} onChange={handleUserId} onClick={(e) => settingBlor(e.target.value)} ref={inputRef} style={{backgroundColor : `#D3D3D3`}} readonly/>
-              </td>
-            </tr>*/}
-            <tr> 
-              <th><span style={{color : "red"}}>*</span>이름</th>
-              <td>
-                <input type="text" value={userName} onChange={handleUserName} />
-              </td>
-              <th><span style={{color : "red"}}>*</span>성별</th>
-              <td className=" gender">
-                <div className="flex-start">
-                  <input type="radio" name="genderSelect" value="남" onChange={handleGender} />
-                  <label for="gender">남</label>
-                </div>
-                <div className="flex-start">
-                  <input type="radio" name="genderSelect" value="여" onChange={handleGender} />
-                  <label for="gender">여</label>
-                </div>
-              </td>
-            </tr>
-            <tr>
-              <th><span style={{color : "red"}}>*</span>생년월일</th>
-              <td>
-                <div className="flex">
-                  <input type='date' value={brith} onChange={handleBrithday} />
-                </div>
-              </td>
-              {/* <th>요양등급</th>
-              <td>
-              <input type="text" />
-              </td> */}
+            <div className="board-wrap">
+              <SubTitle explanation={"회원 등록 시 ID는 연락처, 패스워드는 생년월일 8자리입니다."} className="margin-bottom" />
+              <table className="margin-bottom2 senior-insert">
+                <tr>
+                  <th>관리기관</th>
+                  <td>
+                    <select onChange={(e) => {seniorGovernmentIdChange(e.target.value)}}>
+                      <option value={''} selected={senior['government_id'] == null}>관리기관선택</option>
+                      {orgListOfHierarchy.map((item, idx) => { return (
+                        <option key={idx} value={item['government_id']} selected={senior['government_id'] == item['government_id']}>
+                          {item['government_name']}
+                        </option>
+                      )})}
+                    </select>
+                  </td>
+                  <th>시행기관</th>
+                  <td>
+                    <select onChange={(e) => {seniorAgencyIdChange(e.target.value)}}>
+                      <option value={''} selected={senior['agency_id'] == null}>시행기관선택</option>
+                      {getAgencyList().map((item, idx) => { return (
+                        <option key={idx} value={item['agency_id']} selected={senior['agency_id'] == item['agency_id']}>
+                          {item['agency_name']}
+                        </option>
+                      )})}
+                    </select>
+                  </td>
+                </tr>
+                <tr>
+                  <th><span style={{color : "red"}}>*</span>이름</th>
+                  <td>
+                    <input type="text"
+                      value={senior['user_name']}
+                      onChange={(e) => {seniorValueChange('user_name', e.target.value)}}
+                      ref={el => seniorRef.current['user_name'] = el}
+                    />
+                  </td>
+                  <th><span style={{color : "red"}}>*</span>성별</th>
+                  <td className=" gender">
+                    <div className="flex-start">
+                      <input type="radio" id="user_gender_m" name="user_gender" value="남"
+                        onChange={(e) => {e.target.checked ? seniorValueChange('user_gender', e.target.value) : null}}
+                        ref={el => seniorRef.current['user_gender']['m'] = el}
+                        />
+                      <label for="user_gender_m">남</label>
+                    </div>
+                    <div className="flex-start">
+                      <input type="radio" id="user_gender_f" name="user_gender" value="여"
+                        onChange={(e) => {e.target.checked ? seniorValueChange('user_gender', e.target.value) : null}}
+                        ref={el => seniorRef.current['user_gender']['f'] = el}
+                        />
+                      <label for="user_gender_f">여</label>
+                    </div>
+                  </td>
+                </tr>
+                <tr>
+                  <th><span style={{color : "red"}}>*</span>생년월일</th>
+                  <td>
+                    <div className="flex">
+                      <input type='date'
+                        value={senior['user_birth']}
+                        onChange={(e) => {seniorValueChange('user_birth', e.target.value)}}
+                        ref={el => seniorRef.current['user_birth'] = el}
+                      />
+                    </div>
+                  </td>
+                </tr>
+                <tr>
+                  <th><span style={{color : "red"}}>*</span>연락처</th>
+                  <td colSpan={3}>
+                    <input type="number" maxLength="11"
+                      value={senior['user_phonenumber']}
+                      onChange={(e) => {seniorValueChange('user_phonenumber', e.target.value)}}
+                      ref={el => seniorRef.current['user_phonenumber'] = el}
+                    />
+                  </td>
+                </tr>
+                <tr>
+                  <th><span style={{color : "red"}}>*</span>주소</th>
+                  <td colSpan={3}>
+                    <input type="text"
+                      value={senior['user_address']}
+                      onChange={(e) => {seniorValueChange('user_address', e.target.value)}}
+                      ref={el => seniorRef.current['user_address'] = el}
+                    />
+                  </td>
+                </tr>
+                <tr>
+                  <th>필요 복약</th>
+                  <td className="medicationTime-td">
+                    <div className="flex">
+                      {medicationTimeCodeList.map((item, idx) => { return (
+                        <span key={idx}>
+                          <input type="checkbox"
+                            name="medicationTimeCodeList"
+                            id={item['medication_time_code']}
+                            value={item['medication_time_code']}
+                            onChange={(e) => {seniorMedicationChange(e.target.value, e.target.checked)}}
+                            checked={senior['seniorMedicationList'].indexOf(item['medication_time_code']) > -1}/>
+                          <label for={item['medication_time_code']}>{item['medication_time_code_name']}</label>
+                        </span>
+                      )})}
+                    </div>
+                  </td>
+                </tr>
+                <tr>
+                  <th>복용중인 약</th>
+                  <td colSpan={3}>
+                    <textarea className="medicine" cols="30" rows="2" value={senior['medication_pill']} onChange={(e) => {seniorValueChange('medication_pill', e.target.value)}} />
+                  </td>
+                </tr>
+                <tr>
+                  <th>비고</th>
+                  <td colSpan={3}>
+                    <textarea className="note" cols="30" rows="2" value={senior['senior_note']} onChange={(e) => {seniorValueChange('senior_note', e.target.value)}} />
+                  </td>
+                </tr>
 
-            </tr>
-            <tr>
-              <th><span style={{color : "red"}}>*</span>연락처</th>
-              <td colSpan={3}>
-                <input type="text" maxLength="13" value={telNum} onChange={handleTelNum} />
-              </td>
-            </tr>
-            <tr>
-              <th><span style={{color : "red"}}>*</span>주소</th>
-              <td colSpan={3}>
-                <input type="text" value={homeAddress} onChange={handleHomeAddress} />
-              </td>
-            </tr>
-            <tr>
-              <th>필요 복약</th>
-              <td className="medicationTime-td">
-                <div className="flex ">
-                  <input type="checkbox" name="medicationSelect" checked={medicineM} onClick={(e) => { handleMedicineM(e) }} /><label for="medicationTime">아침</label>
-                  <input type="checkbox" name="medicationSelect" checked={medicineL} onClick={(e) => { handleMedicineL(e) }} /><label for="medicationTime">점심</label>
-                  <input type="checkbox" name="medicationSelect" checked={medicineD} onClick={(e) => { handleMedicineD(e) }} /><label for="medicationTime">저녁</label>
-                </div>
-              </td>
-            </tr>
-            <tr>
-              <th>복용중인 약</th>
-              <td colSpan={3}>
-                <textarea className="medicine" cols="30" rows="2" value={medication} onChange={handleMedication}></textarea>
-              </td>
-            </tr>
-            <tr>
-              <th>비고</th>
-              <td colSpan={3}>
-                <textarea className="note" cols="30" rows="2" value={note} onChange={handleNote}></textarea>
-              </td>
-            </tr>
-
-            {/* <tr>
-              <th>기저질환</th>
-              <td colSpan={3}>
-                <textarea cols="30" rows="10"></textarea>
-              </td>
-            </tr> */}
-          </table>
-          <div className="btn-wrap flex-center">
-            <Button
-              className={"btn-small gray-btn"}
-              btnName={"등록"}
-              onClick={() => {
-                InsertUserData();
-              }}
-            />
-          </div>
-        </div>
+                {/* <tr>
+                  <th>기저질환</th>
+                  <td colSpan={3}>
+                    <textarea cols="30" rows="10"></textarea>
+                  </td>
+                </tr> */}
+              </table>
+              <div className="btn-wrap flex-center">
+                <button className={"btn-small gray-btn"} onClick={seniorInsert}>등록</button>
+              </div>
+            </div>
           </div>
         </div>
       ) : null}
 
client/views/component/Modal_SeniorInsert_back_230329.jsx (added)
+++ client/views/component/Modal_SeniorInsert_back_230329.jsx
@@ -0,0 +1,271 @@
+import React from "react";
+import Button from "./Button.jsx";
+import SubTitle from "./SubTitle.jsx";
+
+export default function Modal({ open, close, header, setModalOpen3, setAddSenior }) {
+   // 사용자 등록 시 초기값 세팅
+  //  const [seniorId, setSeniorId] = React.useState("");
+   const [userName, setUserName] = React.useState("");
+   const [gender, setGender] = React.useState("");
+   const [brith, setBrith] = React.useState("");
+   const [telNum, setTelNum] = React.useState("");
+   const [homeAddress, setHomeAddress] = React.useState("");
+   const [medicineM, setMedicineM] = React.useState(false);
+   const [medicineL, setMedicineL] = React.useState(false);
+   const [medicineD, setMedicineD] = React.useState(false);
+   const [medication, setMedication] = React.useState("");
+   const [note, setNote] = React.useState("");
+
+  // //id blor 처리 진행 
+  // const inputRef = React.useRef();
+  // const settingBlor = (e) => {
+  //   inputRef.current.blur();
+  // }
+
+     // 등록 후 초기화 진행
+  const dataReset = () => {
+    // setSeniorId("");
+    setUserName("");
+    setGender("");
+    setBrith("");
+    setTelNum("");
+    setHomeAddress("");
+    setMedicineM("");
+    setMedicineL("");
+    setMedicineD("");
+    setMedication("");
+    setNote("");
+  }
+   //-------- 변경되는 데이터 Handler 설정 --------//
+  // const handleUserId = (e) => {
+  //   console.log(e.target.value);
+  //   setSeniorId(e.target.value);
+  // };
+  const handleUserName = (e) => {
+    e.target.value=e.target.value.replace(/[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣|a-z|A-Z]/g, '');
+    setUserName(e.target.value);
+  };
+  const handleGender = (e) => {
+    setGender(e.target.value);
+  };
+  const handleBrithday = (e) => {
+    setBrith(e.target.value);
+  };
+  const handleTelNum = (e) => {
+    e.target.value = e.target.value.replace(/[^0-9]/g, '').replace(/^(\d{2,3})(\d{3,4})(\d{4})$/, `$1-$2-$3`);
+    setTelNum(e.target.value);
+  };
+  const handleHomeAddress = (e) => {
+    setHomeAddress(e.target.value);
+  };
+  const handleMedicineM = (e) => {
+    setMedicineM(e.target.checked);
+  };
+  const handleMedicineL = (e) => {
+    setMedicineL(e.target.checked);
+  };
+  const handleMedicineD = (e) => {
+    setMedicineD(e.target.checked);
+  };
+  const handleMedication = (e) => {
+    setMedication(e.target.value);
+  };
+  const handleNote = (e) => {
+    setNote(e.target.value);
+  };
+
+  //-------- 등록 버튼 동작 수행 영역 시작 --------//
+  // 대상자 정보 등록을 위한 함수 
+  const InsertUserData = () => {
+    //-------- 유효성 체크 --------//
+    if(userName == ""){
+      alert("이름을 입력해 주세요.");
+      return ;
+    } else if(gender == "") {
+      alert("성별을 선택해 주세요.");
+      return ;
+    } else if(brith == "") {
+      alert("생년월일을 선택해 주세요.");
+      return ;
+    } else if(telNum == "") {
+      alert("연락처를 입력해 선택해 주세요.");
+      return ;
+    } else if(homeAddress == "") {
+      alert("주소를 선택해 주세요.");
+      return ;
+    }
+    var insertBtn = confirm("등록하시겠습니까?");
+    if (insertBtn) {
+      fetch("/user/insertUserData.json", {
+        method: "POST",
+        headers: {
+          'Content-Type': 'application/json; charset=UTF-8'
+        },
+        body: JSON.stringify({
+          user_name: userName,
+          user_gender: gender,
+          user_birth: brith,
+          user_phonenumber: telNum,
+          user_address: homeAddress,
+          agency_id: 'AGENCY01',
+          government_id: 'GOVERNMENT01',
+          authority: 'SENIOR01',
+        }),
+      }).then((response) => response.json()).then((data) => {
+        console.log("대상자 정보 등록");
+        InsertUserPillData();
+      }).catch((error) => {
+        console.log('insertUserData() /user/insertUserData.json error : ', error);
+      });
+    } else {
+      return;
+    }
+  };
+  // 대상자 약 복용 정보 등록을 위한 함수 
+  const InsertUserPillData = () => {
+    fetch("/user/insertSeniorMadication.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({
+        user_phonenumber: telNum,
+        breakfast_medication_check: medicineM,
+        lunch_medication_check: medicineL,
+        dinner_medication_check: medicineD,
+        medication_pill: medication,
+        senior_note: note,
+      }),
+    }).then((response) => response.json()).then((data) => {
+      console.log("약 정보 등록");
+      dataReset();
+      setAddSenior(true)
+      alert("등록 되었습니다.");
+      noticeModalClose()
+
+    }).catch((error) => {
+      console.log('InsertUserPillData() /user/insertSeniorMadication.json error : ', error);
+    });
+  };
+  //-------- 등록 버튼 동작 수행 영역 끝 --------/
+  //-------- 모달 종료 -------->
+  const noticeModalClose = () => {
+    dataReset();
+    setModalOpen3(false);
+  };
+  return (
+    <div class={open ? "openModal modal" : "modal"}>
+      {open ? (
+        <div className="modal-inner">
+          <div className="modal-header flex">
+            {header}
+            <Button className={"close"} onClick={noticeModalClose} btnName={"X"} />
+          </div>
+          <div className="modal-main">
+          <div className="board-wrap">
+          <SubTitle explanation={"회원 등록 시 ID는 연락처, 패스워드는 생년월일 8자리입니다."} className="margin-bottom" />
+          <table className="margin-bottom2 senior-insert">
+            {/* <tr>
+              <th>대상자등록번호</th>
+              <td colSpan={3} className="flex">
+                <input type="text" placeholder="생성하기 버튼 클릭 시 자동으로 생성됩니다."/>
+                <Button
+              className={"btn-large gray-btn"}
+              btnName={"생성하기"}
+            />
+              </td>
+            </tr> */}
+            {/* <tr>
+              <th>아이디</th>
+              <td>
+                <input type="text" value={`${telNum}_${userName}`.replace(/[-]/g,'')} onChange={handleUserId} onClick={(e) => settingBlor(e.target.value)} ref={inputRef} style={{backgroundColor : `#D3D3D3`}} readonly/>
+              </td>
+            </tr>*/}
+            <tr> 
+              <th><span style={{color : "red"}}>*</span>이름</th>
+              <td>
+                <input type="text" value={userName} onChange={handleUserName} />
+              </td>
+              <th><span style={{color : "red"}}>*</span>성별</th>
+              <td className=" gender">
+                <div className="flex-start">
+                  <input type="radio" name="genderSelect" value="남" onChange={handleGender} />
+                  <label for="gender">남</label>
+                </div>
+                <div className="flex-start">
+                  <input type="radio" name="genderSelect" value="여" onChange={handleGender} />
+                  <label for="gender">여</label>
+                </div>
+              </td>
+            </tr>
+            <tr>
+              <th><span style={{color : "red"}}>*</span>생년월일</th>
+              <td>
+                <div className="flex">
+                  <input type='date' value={brith} onChange={handleBrithday} />
+                </div>
+              </td>
+              {/* <th>요양등급</th>
+              <td>
+              <input type="text" />
+              </td> */}
+
+            </tr>
+            <tr>
+              <th><span style={{color : "red"}}>*</span>연락처</th>
+              <td colSpan={3}>
+                <input type="text" maxLength="13" value={telNum} onChange={handleTelNum} />
+              </td>
+            </tr>
+            <tr>
+              <th><span style={{color : "red"}}>*</span>주소</th>
+              <td colSpan={3}>
+                <input type="text" value={homeAddress} onChange={handleHomeAddress} />
+              </td>
+            </tr>
+            <tr>
+              <th>필요 복약</th>
+              <td className="medicationTime-td">
+                <div className="flex ">
+                  <input type="checkbox" name="medicationSelect" checked={medicineM} onClick={(e) => { handleMedicineM(e) }} /><label for="medicationTime">아침</label>
+                  <input type="checkbox" name="medicationSelect" checked={medicineL} onClick={(e) => { handleMedicineL(e) }} /><label for="medicationTime">점심</label>
+                  <input type="checkbox" name="medicationSelect" checked={medicineD} onClick={(e) => { handleMedicineD(e) }} /><label for="medicationTime">저녁</label>
+                </div>
+              </td>
+            </tr>
+            <tr>
+              <th>복용중인 약</th>
+              <td colSpan={3}>
+                <textarea className="medicine" cols="30" rows="2" value={medication} onChange={handleMedication}></textarea>
+              </td>
+            </tr>
+            <tr>
+              <th>비고</th>
+              <td colSpan={3}>
+                <textarea className="note" cols="30" rows="2" value={note} onChange={handleNote}></textarea>
+              </td>
+            </tr>
+
+            {/* <tr>
+              <th>기저질환</th>
+              <td colSpan={3}>
+                <textarea cols="30" rows="10"></textarea>
+              </td>
+            </tr> */}
+          </table>
+          <div className="btn-wrap flex-center">
+            <Button
+              className={"btn-small gray-btn"}
+              btnName={"등록"}
+              onClick={() => {
+                InsertUserData();
+              }}
+            />
+          </div>
+        </div>
+          </div>
+        </div>
+      ) : null}
+    </div>
+  );
+}
client/views/component/Pagination.jsx
--- client/views/component/Pagination.jsx
+++ client/views/component/Pagination.jsx
@@ -1,17 +1,57 @@
 import React from "react";
 import styled from "styled-components";
 
-export default function Pagination({ total, limit, page, setPage }) {
-    const numPages = Math.ceil(total / limit);
+export default function Pagination({ currentPage, perPage, totalCount, maxRange, click }) {
+
+    const startPage = () => {
+        return Math.floor((currentPage - 1) / maxRange) * maxRange + 1;
+    }
+    const endPage = () => {
+        if (maxEndPage() < currentEndPage()) {
+            return maxEndPage();
+        } else {
+            return currentEndPage();
+        }
+    }
+    const currentEndPage = () => {
+        return maxRange * Math.ceil((currentPage / maxRange));
+    }
+    const maxEndPage = () => {
+        return Math.ceil(totalCount / perPage);
+    }
+    const createRange = () => {
+        var range = [];
+        for (var i = startPage(); i <= endPage(); i++) {
+            range.push(i);
+        }
+        return range;
+    }
+
+    const excute = (i) => {
+        if (i >= 1 && i <= maxEndPage()) {
+            if (i != currentPage) {
+                click(i);//부모 function 실행
+            } else {
+                return;
+            }
+        } else {
+            alert('이동할 페이지가 없습니다.');
+        }
+    }
 
     return (
         <>
             <Paging>
-                <button onClick={() => setPage(page - 1)} disabled={page === 1}>&lt;</button>
-                {Array(numPages).fill().map((_, i) => (
-                    <button key={i + 1} onClick={() => setPage(i + 1)} aria-current={page === i + 1 ? "page" : null} className={page === i + 1 ? "PagingBtn" : null}> {i + 1} </button>
+                <button onClick={() => excute(currentPage - 1)} disabled={currentPage === 1}>&lt;</button>
+                {createRange().map((page, i) => (
+                    <button
+                        key={page} onClick={() => excute(page)}
+                        className={currentPage === page ? "PagingBtn" : null}
+                        aria-current={currentPage === page ? "page" : null}>
+                        {page}
+                    </button>
                 ))}
-                <button onClick={() => setPage(page + 1)} disabled={page === numPages}>&gt;</button>
+                <button onClick={() => excute(currentPage + 1)} disabled={currentPage === maxEndPage()}>&gt;</button>
             </Paging>
         </>
     );
client/views/index.html
--- client/views/index.html
+++ client/views/index.html
@@ -7,7 +7,7 @@
         <meta name="description" content="Node React Web">
         <link rel="icon" href="" />
         <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=	557664ec353e27affe3d6c3c513b7183"></script>
-        <title>올잇메디</title>
+        <title>시니어 케어 시스템</title>
     </head>
 
     <body>
client/views/index.jsx
--- client/views/index.jsx
+++ client/views/index.jsx
@@ -7,6 +7,10 @@
 import React from "react";
 import ReactDOM from "react-dom/client";
 import { BrowserRouter } from "react-router-dom";
+import { Provider } from "react-redux";
+
+//Application의 전역 상태값(변수) 저장소(Store) 관리 Component
+import AppStore from "./pages/AppStore.jsx";
 
 //Application Root component
 import App from "./pages/App.jsx";
@@ -20,6 +24,8 @@
 const root = ReactDOM.createRoot(document.getElementById("root"));
 root.render(
   <BrowserRouter>
-    <App />
+    <Provider store={AppStore}>
+      <App />
+    </Provider>
   </BrowserRouter>
 );
client/views/layout/Header.jsx
--- client/views/layout/Header.jsx
+++ client/views/layout/Header.jsx
@@ -1,13 +1,32 @@
 import React from "react";
+import { useSelector } from "react-redux";
+
 import MenuIcon from "@mui/icons-material/Menu";
 import Weather from "../pages/main/Weather.jsx";
 import PersonIcon from "@mui/icons-material/Person";
 import { useNavigate } from "react-router";
 import logo from "../../resources/files/images/logo.png";
 
-function Header({ title }) {
+function Header() {
   const navigate = useNavigate();
-  const [headerData, setHeaderData] = React.useState(0);
+
+  //전역 변수 저장 객체
+  const state = useSelector((state) => {return state});
+
+  //App Title
+  const [title, setTitle] = React.useState('');
+
+  React.useEffect(() => {
+    if (state.loginUser['authority'] == 'ROLE_ADMIN') {
+      setTitle('올잇메디');
+    } else if (state.loginUser['authority'] == 'ROLE_GOVERNMENT') {
+      setTitle(state.loginUser['government_name']);
+    } else if (state.loginUser['authority'] == 'ROLE_AGENCY') {
+      setTitle(state.loginUser['agency_name']);
+    } else if (state.loginUser['authority'] == 'ROLE_GUARDIAN') {
+      setTitle('보호자');
+    }
+  }, [state.loginUser['authority']]);
 
   return (
     <header>
@@ -17,8 +36,8 @@
         <div className="page-title flex flex-align">
           {/* <MenuIcon /> */}
           <div className="info-wrap flex">
-            <div className="usericon"><PersonIcon sx={{ width:48, height:48,}} /></div>
-            <p className="header-info-id">admin1</p>            
+            {/* <div className="usericon"><PersonIcon sx={{ width:48, height:48,}} /></div> */}
+            <p className="header-info-id">{state.loginUser['user_name']}({state.loginUser['user_id']})</p>            
           </div>
         <Weather />
         </div>
client/views/layout/Menu.jsx
--- client/views/layout/Menu.jsx
+++ client/views/layout/Menu.jsx
@@ -12,6 +12,26 @@
   }
   const navigate = useNavigate();
 
+  //로그아웃
+  const logout = () => {
+    fetch("/user/logout.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      /* body: JSON.stringify({}), */
+    }).then((response) => response.json()).then((data) => {
+      console.log("로그아웃 결과 : ", data);
+      if (data == true) {
+        navigate('/Main');
+      } else {
+        alert('로그아웃 실패, 관리자에게 문의바랍니다.');
+      }
+    }).catch((error) => {
+      console.log('logout() /user/logout.json error : ', error);
+    });
+  };
+
   return (
  <>
       <nav
@@ -30,7 +50,7 @@
             <div className="info-id" ><span onClick={() => {
               navigate("/Join");
             }}>계정추가</span></div>
-            <div className="logout"><span>로그아웃</span></div>
+            <div className="logout" onClick={logout}><span>로그아웃</span></div>
           </div>
       </nav>
         
client/views/pages/App.jsx
--- client/views/pages/App.jsx
+++ client/views/pages/App.jsx
@@ -4,6 +4,11 @@
  * @dscription : React를 활용한 Client단 구현 대상인 Application의 시작점(Index) Component 입니다.
  */
 import React from "react";
+import { useSelector, useDispatch } from "react-redux";
+import { useLocation, /* useNavigate */ } from "react-router";
+
+//Application의 전역 상태값(변수) 저장소(Store) 관리 Component
+import { setLoginUser } from "./AppStore.jsx";
 
 //Application의 Route 정보를 관리하는 Component
 import AllApp, {AdminApp, GovernmentApp, AgencyApp, GuardianApp} from "./AppRoute.jsx";
@@ -12,44 +17,87 @@
 import Header from "../layout/Header.jsx";
 import Menu from "../layout/Menu.jsx";
 import Login from "./login/Login.jsx";
-import { useLocation, useNavigate } from "react-router";
 import Weather from "./main/Weather.jsx";
 
 function App() {
   const location = useLocation();
-  const navigate = useNavigate();
-  const [isLogin, setIsLogin] = React.useState(true);
+  //const navigate = useNavigate();
 
-  const getLogin = () => {
-    setIsLogin(true);
-    navigate("/Main");
+  //전역 변수 저장 객체
+  const state = useSelector((state) => {return state});
+  const dispatch = useDispatch();
+
+  //로그인 여부
+  const [isLogin, setIsLogin] = React.useState(false);
+  
+  //로그인에 따라 각기 다른 App 주입 대상 변수(AdminApp, GovernmentApp, AgencyApp, GuardianApp)
+  const [appRoute, setAppRoute] = React.useState(null);
+  const [menuItems, setMenuItems] = React.useState(null);
+  
+  //로그인 사용자 조회
+  const loginUserSelectOne = (clientLoginCheck) => {
+    fetch("/user/loginUserSelectOne.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({}),
+    }).then((response) => response.json()).then((data) => {
+      console.log("로그인 결과 : ", data);
+      //로그인 사용자 정보 전역 변수에 저장
+      dispatch(setLoginUser(data));
+      //클라이언트 로그인 체크 (콜백)
+      clientLoginCheck(data);
+    }).catch((error) => {
+      console.log('login() /user/loginUserSelectOne.json error : ', error);
+    });
   };
 
+  //URL 변경 시, 발생 이벤트(hook)
+  React.useEffect(() => {
+    console.log('location : ', location);
+    loginUserSelectOne((loginResultData) => {
+      //console.log('loginResultData : ', loginResultData);
+      //console.log('isLogin : ', isLogin, ', authority : ', loginResultData['authority']);
 
-  const menuItems = AgencyApp.menuItems;  //AdminApp, GovernmentApp, AllApp, AgencyApp, GuardianApp 
-  const AppRoute = AgencyApp.AppRoute;
+      //로그인 유무(로그인 정보가 있으면 True, 없으면 False)
+      let isLogin = (loginResultData != null && loginResultData['user_id'] != null);
+      setIsLogin(isLogin);
 
+      //로그인 -> 권한에 따른 App 주입 
+      if (isLogin == true) {
+        if (loginResultData['authority'] == 'ROLE_ADMIN') {
+          setMenuItems(AdminApp.menuItems);
+          setAppRoute(<AdminApp.AppRoute/>);
+        } else if (loginResultData['authority'] == 'ROLE_GOVERNMENT') {
+          setMenuItems(GovernmentApp.menuItems);
+          setAppRoute(<GovernmentApp.AppRoute/>);
+        } else if (loginResultData['authority'] == 'ROLE_AGENCY') {
+          setMenuItems(AgencyApp.menuItems);
+          setAppRoute(<AgencyApp.AppRoute/>);
+        } else if (loginResultData['authority'] == 'ROLE_GUARDIAN') {
+          setMenuItems(GuardianApp.menuItems);
+          setAppRoute(<GuardianApp.AppRoute/>);
+        } else {
+          alert('권한 관련 에러 - 관리자에게 문의바랍니다.');
+          console.log('권한 관련 에러 - 관리자에게 문의바랍니다 : ', loginResultData);
+        }
+      }
+    });
+  }, [location]);
 
-  const { title } = menuItems.find(
-    (item) =>
-      item.path === location.pathname ||
-      location.pathname.startsWith(item.prefix) ||
-      item.childrens?.some((child) => location.pathname.startsWith(child.path))
-  ) ?? { title: '' };
 
   return (
     <div id="App">
-      {isLogin ? (
+      {isLogin == true ? (
         <div id="layout">
-          <Header title={title} />
-          <Menu items={menuItems}/>
+          <Header/>
+          <Menu items={menuItems != null ? menuItems : null}/>
           <div id="pages">
-            <AppRoute />
+            {appRoute != null ? appRoute : null}
           </div>
         </div>
-      ) : (
-        <Login getLogin={getLogin} />
-      )}
+      ) : (<Login/>)}
     </div>
   );
 }
client/views/pages/AppRoute.jsx
--- client/views/pages/AppRoute.jsx
+++ client/views/pages/AppRoute.jsx
@@ -17,7 +17,6 @@
 import ApartmentIcon from '@mui/icons-material/Apartment';
 import LocalHospitalIcon from '@mui/icons-material/LocalHospital';
 
-import Test from "./test/Test.jsx";
 import Main_government from "./main/Main_government.jsx";
 import Main_guardian from "./main/Main_guardian.jsx";
 import Main_agency from "./main/Main_agency.jsx";
@@ -255,6 +254,7 @@
 function AllAppRoute() {
   return (
     <Routes>
+
       <Route path="/Medicalcare" element={<Medicalcare />}></Route>
       <Route path="/Healthcare" element={<Healthcare />}></Route>
       <Route path="/QuestionConfirm/:qnaIdx" element={<QuestionConfirm />}></Route>
@@ -332,7 +332,6 @@
       <Route path="/SeniorEdit/:seniorId" element={<SeniorEdit />}></Route>
       <Route path="/AgencyInsert" element={<AgencyInsert />}></Route>
       <Route path="/Join" element={<Join />}></Route>
-      <Route path="/Test" element={<Test />}></Route>
       <Route path="/Main" element={<Main />}></Route>
       <Route
         path="/EquipmentRentalInsert"
@@ -423,9 +422,9 @@
 function AdminAppRoute() {
   return (
     <Routes>
+
       <Route path="/Medicalcare" element={<Medicalcare />}></Route>
       <Route path="/Healthcare" element={<Healthcare />}></Route>
-      <Route path="/Test" element={<Test />}></Route>
       <Route path="/Main" element={<Main />}></Route>
       <Route
         path="/EquipmentRentalInsert"
@@ -460,6 +459,9 @@
       <Route path="/EquipmentManagementSelectAdd" element={<EquipmentManagementSelectAdd />}></Route>
       <Route path="/UserAuthoriySelect" element={<UserAuthoriySelect />}></Route>
       <Route path="/QandAConfirm" element={<QandAConfirm />}></Route>
+      <Route path="/Join" element={<Join />}></Route>
+      <Route path="/SeniorEdit" element={<SeniorEdit />}></Route>
+      <Route path="/SeniorSelectOne" element={<SeniorSelectOne />}></Route>      
     </Routes>
   );
 }
@@ -468,7 +470,7 @@
 const GovernmentAppMenuItems = [
   {
     title: "Home",
-    path: "/Main_government",
+    path: "/Main",
     icon: <HouseIcon sx={{ fontSize: 20, color: "#333333", marginRight: 1 }} />,
   },
   {
@@ -520,19 +522,20 @@
         title: "위험 기준 관리",
         path: "/RiskSet",
       },
-      {
+      /* {
         title: "사용자 권한 관리",
         path: "/AuthorityManagement",
-      },
+      }, */
     ],
   },
 ];
 function GovernmentAppRoute() {
   return (
     <Routes>
+
       <Route path="/Medicalcare" element={<Medicalcare />}></Route>
       <Route path="/Healthcare" element={<Healthcare />}></Route>
-      <Route path="/Main_government" element={<Main_government />}></Route>
+      <Route path="/Main" element={<Main_government />}></Route>
       <Route path="/AgencySelect" element={<AgencySelect />}></Route>
       <Route path="/UserSelectOk" element={<UserSelectOk />}></Route>      
       <Route
@@ -554,7 +557,7 @@
         element={<UserAuthoriySelect />}
       ></Route>
       <Route path="/RiskSet" element={<RiskSet />}></Route>
-      <Route path="/AuthorityManagement" element={<AuthorityManagement />}></Route>
+      {/* <Route path="/AuthorityManagement" element={<AuthorityManagement />}></Route> */}
       <Route path="/QandASelect" element={<QandASelect />}></Route>
       <Route path="/QandAConfirm" element={<QandAConfirm />}></Route>
       <Route path="/QandAInsert" element={<QandAInsert />}></Route>
@@ -568,7 +571,7 @@
 const AgencyAppMenuItems = [
   {
     title: "Home",
-    path: "/Main_agency",
+    path: "/Main",
     icon: <HouseIcon sx={{ fontSize: 20, color: "#333333", marginRight: 1 }} />,
   },
   {
@@ -621,12 +624,13 @@
 function AgencyAppRoute() {
   return (
     <Routes>
+
       <Route path="/Medicalcare" element={<Medicalcare />}></Route>
       <Route path="/Healthcare" element={<Healthcare />}></Route>
       <Route path="/Join" element={<Join />}></Route>
       <Route path="/QuestionSelect" element={<QuestionSelect />}></Route>
       
-      <Route path="/Main_agency" element={<Main_agency />}></Route>
+      <Route path="/Main" element={<Main_agency />}></Route>
       <Route path="/UserAuthoriySelect_agency" element={<UserAuthoriySelect_agency />}></Route>
       <Route path="/SeniorEdit/:seniorId" element={<SeniorEdit />}></Route>
       <Route path="/SeniorSelectOne/:seniorId" element={<SeniorSelectOne />}></Route>
@@ -670,7 +674,7 @@
 const GuardianAppMenuItems = [
   {
     title: "Home",
-    path: "/Main_guardian",
+    path: "/Main",
     icon: <HouseIcon sx={{ fontSize: 20, color: "#333333", marginRight: 1 }} />,
   },
   {
@@ -691,8 +695,8 @@
 function GuardianAppRoute() {
   return (
     <Routes>
-       <Route path="/GuardianStatistics" element={<GuardianStatistics />}></Route>
-      <Route path="/Main_guardian" element={<Main_guardian />}></Route>
+      <Route path="/GuardianStatistics" element={<GuardianStatistics />}></Route>
+      <Route path="/Main" element={<Main_guardian />}></Route>
       <Route path="/QuestionSelect" element={<QuestionSelect />}></Route>
       <Route path="/QuestionConfirm/:qnaIdx" element={<QuestionConfirm />}></Route>
       
 
client/views/pages/AppStore.jsx (added)
+++ client/views/pages/AppStore.jsx
@@ -0,0 +1,24 @@
+import { configureStore, createSlice } from "@reduxjs/toolkit";
+
+//로그인 정보
+const loginUser = createSlice({
+    name: 'createSlice',
+    initialState: {},
+    reducers: {
+        setLoginUser(stats, action) {
+            for (let key in action.payload) {
+                stats[key] = action.payload[key];
+            }
+        }
+    }
+})
+//로그인 정보 변경
+const { setLoginUser } = loginUser.actions;
+
+export default configureStore({
+    reducer: {
+        loginUser: loginUser.reducer,
+    }
+})
+
+export { setLoginUser };(파일 끝에 줄바꿈 문자 없음)
client/views/pages/join/Join.jsx
--- client/views/pages/join/Join.jsx
+++ client/views/pages/join/Join.jsx
@@ -1,124 +1,359 @@
 import React from "react";
 import Button from "../../component/Button.jsx";
-import { useNavigate } from "react-router";
+import { useNavigate, useLocation } from "react-router";
+import { useSelector } from "react-redux";
+
+import CommonUtil from "../../../resources/js/CommonUtil.js";
+
 export default function Join() {
   const navigate = useNavigate();
+  const location = useLocation();
+  const defaultAuthority = CommonUtil.isEmpty(location.state) ? null : location.state['authority'];
+  const defaultAgencyId = CommonUtil.isEmpty(location.state) ? null : location.state['agency_id'];
+  const defaultGovernmentId = CommonUtil.isEmpty(location.state) ? null :location.state['government_id'];
+
+
+
+  /**** 기본 조회 데이터 (시작) ****/
+  //전역 변수 저장 객체
+  const state = useSelector((state) => {return state});
+
+  //권한 타입 종류
+  const [authorities, setAuthorities] = React.useState([]);
+  //권한 타입 종류 목록 조회
+  const authoritiesSelect = () => {
+    fetch("/common/systemCode/authoritiesSelect.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({}),
+    }).then((response) => response.json()).then((data) => {
+      console.log("권한 타입 종류 목록 조회 : ", data);
+      setAuthorities(data);
+    }).catch((error) => {
+      console.log('authoritiesSelect() /common/systemCode/authoritiesSelect.json error : ', error);
+    });
+  };
+  //기관 계층 구조 목록
+  const [orgListOfHierarchy, setOrgListOfHierarchy] = React.useState([]);
+  //기관(관리, 시행) 계층 구조 목록 조회
+  const orgSelectListOfHierarchy = () => {
+    fetch("/org/orgSelectListOfHierarchy.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({}),
+    }).then((response) => response.json()).then((data) => {
+      console.log("기관(관리, 시행) 계층 구조 목록 조회 : ", data);
+      setOrgListOfHierarchy(data);
+    }).catch((error) => {
+      console.log('orgSelectListOfHierarchy() /org/orgSelectListOfHierarchy.json error : ', error);
+    });
+  };
+  const getAgencyList = () => {
+    const government = orgListOfHierarchy.find(item => item['government_id'] == user['government_id']);
+    if (CommonUtil.isEmpty(government) || CommonUtil.isEmpty(government['agencyList'])) {
+      return [];
+    } else {
+      return government['agencyList'];
+    }
+  }
+  /**** 기본 조회 데이터 (종료) ****/
+
+  //로그인 중복 확인
+  const [isIdCheck, setIsIdCheck] = React.useState(false);
+
+  //등록할 사용자 정보
+  const [user, setUser] = React.useState({
+    'user_id': null,
+    'user_name': null,
+    'user_password': null,
+    'user_password_check': null,
+    'user_phonenumber': null,
+    'user_birth': null,
+    'user_gender': null,
+    'user_address': null,
+    'user_email': null,
+    'authority': CommonUtil.isEmpty(defaultAuthority) ? state.loginUser['authority'] : defaultAuthority,
+    'agency_id': CommonUtil.isEmpty(defaultAgencyId) ? state.loginUser['agency_id'] : defaultAgencyId,
+    'government_id': CommonUtil.isEmpty(defaultGovernmentId) ? state.loginUser['government_id'] : defaultGovernmentId,
+  });
+  //각 데이터별로 Dom 정보 담을 Ref 생성
+  const userRefInit = JSON.parse(JSON.stringify(user));
+  userRefInit['user_gender'] = {};
+  userRefInit['user_id_check_button'] = null;
+  const userRef = React.useRef(userRefInit);
+
+  //등록할 사용자 정보 변경
+  const userValueChange = (targetKey, value) => {
+    let newUser = JSON.parse(JSON.stringify(user));
+    newUser[targetKey] = value;
+    setUser(newUser);
+  }
+  //등록할 사용자의 권한 구분 변경
+  const userAuthorityChange = (value) => {
+    let newUser = JSON.parse(JSON.stringify(user));
+    newUser['authority'] = value;
+    newUser['government_id'] = null;
+    newUser['agency_id'] = null;
+    setUser(newUser);
+  }
+  //등록할 사용자의 관리기관 변경
+  const userGovernmentIdChange = (value) => {
+    let newUser = JSON.parse(JSON.stringify(user));
+    if (CommonUtil.isEmpty(value) == true) {
+      newUser['government_id'] = null;
+    } else {
+      newUser['government_id'] = value;
+    }
+    newUser['agency_id'] = null;
+    setUser(newUser);
+  }
+  //등록할 사용자의 시행기관 변경
+  const userAgencyIdChange = (value) => {
+    let newUser = JSON.parse(JSON.stringify(user));
+    if (CommonUtil.isEmpty(value) == true) {
+      newUser['agency_id'] = null;
+    } else {
+      newUser['agency_id'] = value;
+    }
+    setUser(newUser);
+  }
+  //로그인 아이디 중복 검사
+  const userIdCheck = () => {
+    fetch("/user/userSelectOne.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(user),
+    }).then((response) => response.json()).then((data) => {
+      console.log("로그인 아이디 중복 검사(아이디를 통한 사용자 조회) : ", data);
+      if (CommonUtil.isEmpty(data) == true) {
+        setIsIdCheck(true);
+        userRef.current['user_password'].focus();
+        alert("사용가능한 아이디 입니다.");
+      } else {
+        setIsIdCheck(false);
+        userRef.current['user_id'].focus();
+        alert("이미 존재하는 아이디 입니다.");
+      }
+    }).catch((error) => {
+      console.log('userIdCheck() /user/userSelectOne.json error : ', error);
+    });
+  }
+
+
+   //사용자 등록 유효성 검사
+   const userInsertValidation = () => {
+    if ((user['authority'] == 'ROLE_GOVERNMENT' || user['authority'] == 'ROLE_AGENCY')
+        && CommonUtil.isEmpty(user['government_id']) == true) {
+      userRef.current['government_id'].focus();
+      alert("관리기관을 선택해 주세요.");
+      return false;
+    }
+
+    if (user['authority'] == 'ROLE_AGENCY' && CommonUtil.isEmpty(user['agency_id']) == true) {
+      userRef.current['agency_id'].focus();
+      alert("시행기관을 선택해 주세요.");
+      return false;
+    }
+
+    if (CommonUtil.isEmpty(user['user_name']) == true) {
+      userRef.current['user_name'].focus();
+      alert("이름을 입력해 주세요.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(user['user_id']) == true) {
+      userRef.current['user_id'].focus();
+      alert("아이디를 입력해 주세요.");
+      return false;
+    }
+    if (isIdCheck == false) {
+      alert("아이디 중복 확인을 해주세요.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(user['user_password']) == true) {
+      userRef.current['user_password'].focus();
+      alert("비밀번호를 입력해 주세요.");
+      return false;
+    }
+    if (user['user_password'] != user['user_password_check']) {
+      userRef.current['user_password_check'].focus();
+      alert("비밀번호가 일치하지 않습니다.");
+      return false;
+    }
+    if (CommonUtil.isEmpty(user['user_phonenumber']) == true) {
+      userRef.current['user_phonenumber'].focus();
+      alert("연락처를 입력해 주세요.");
+      return false;
+    }
+
+    /* if (CommonUtil.isEmpty(user['user_email']) == true) {
+      userRef.current['user_email'].focus();
+      alert("이메일을 입력해 주세요.");
+      return false;
+    } */
+
+    return true;
+  }
+
+  //사용자 등록
+  const userInsert = () => {
+    if (userInsertValidation() == false) {
+      return;
+    }
+
+    fetch("/user/userInsert.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(user),
+    }).then((response) => response.json()).then((data) => {
+      console.log("사용자 등록 결과(건수) : ", data);
+      if (data > 0) {
+        alert("계정생성완료");
+        navigate(-1);
+      } else {
+        alert("계정생성에 실패하였습니다. 관리자에게 문의바랍니다.");
+      }
+    }).catch((error) => {
+      console.log('userInsert() /user/userInsert.json error : ', error);
+    });
+  }
+  
+  //Mounted
+  React.useEffect(() => {
+    authoritiesSelect();
+    orgSelectListOfHierarchy();
+  }, []);
+  
+
   return (
       <div className="container row flex-center join-login">
         <div className="join-group">
           <h3>계정생성</h3>
           <div className="join-inner">
-            {/* <div>
+            <div>
               <div className="flex-start margin-bottom2">
-                <label className="flex25">구분</label>
-                <select name="division" id="section">
-                  <option value="manager">관리자</option>
-                  <option value="individual">개인</option>
-                  <option value="protection_agency">보호기관</option>
-                  <option value="hospital">병원</option>
-                  <option value="government">지자체</option>
+                <label className="flex25"><span style={{color : "red"}}>*</span>사용자구분</label>
+                <select name="division" id="section" onChange={(e) => {userAuthorityChange(e.target.value)}}>
+                    <option value="ROLE_ADMIN" selected={user['authority'] == "ROLE_ADMIN"}>시스템 관리자</option>
+                    <option value="ROLE_GOVERNMENT" selected={user['authority'] == "ROLE_GOVERNMENT"}>기관 관리자</option>
+                    <option value="ROLE_AGENCY" selected={user['authority'] == "ROLE_AGENCY"}>보호사</option>
                 </select>
               </div>
-            </div> */}
+            </div>
+
+            {user['authority'] == 'ROLE_GOVERNMENT' || user['authority'] == 'ROLE_AGENCY' ?
+              <div>
+                <div className="flex-start margin-bottom2">
+                  <label className="flex25" htmlFor="name"><span style={{color : "red"}}>*</span>관리기관</label>
+                  <select onChange={(e) => {userGovernmentIdChange(e.target.value)}} ref={el => userRef.current['government_id'] = el}>
+                    <option value={''} selected={user['government_id'] == null}>관리기관선택</option>
+                    {orgListOfHierarchy.map((item, idx) => { return (
+                      <option key={idx} value={item['government_id']} selected={user['government_id'] == item['government_id']}>
+                        {item['government_name']}
+                      </option>
+                    )})}
+                  </select>
+                </div>
+              </div>
+            : null}
+
+            {user['authority'] == 'ROLE_AGENCY' ?
+              <div>
+                <div className="flex-start margin-bottom2">
+                  <label className="flex25" htmlFor="name"><span style={{color : "red"}}>*</span>시행기관</label>
+                  <select onChange={(e) => {userAgencyIdChange(e.target.value)}} ref={el => userRef.current['agency_id'] = el}>
+                    <option value={''} selected={user['agency_id'] == null}>시행기관선택</option>
+                    {getAgencyList().map((item, idx) => { return (
+                      <option key={idx} value={item['agency_id']} selected={user['agency_id'] == item['agency_id']}>
+                        {item['agency_name']}
+                      </option>
+                    )})}
+                  </select>
+                </div>
+              </div>
+            : null}
+
             <div>
               <div className="flex-start margin-bottom2">
-                <label className="flex25" htmlFor="name">
-                  기관명
-                </label>
-                <input
-                  type="text"
-                  name="name"
-                  placeholder=""
-                  autocomplete="off"
-                  id="name"
+                <label className="flex25" htmlFor="name"><span style={{color : "red"}}>*</span>이름</label>
+                <input type="text"
+                  value={user['user_name']}
+                  onChange={(e) => {userValueChange('user_name', e.target.value)}}
+                  ref={el => userRef.current['user_name'] = el}
                 />
               </div>
             </div>
-            <div>
-              <div className="flex-start margin-bottom2">
-                <label className="flex25" htmlFor="name">
-                  이름
-                </label>
-                <input
-                  type="text"
-                  name="name"
-                  placeholder=""
-                  autocomplete="off"
-                  id="name"
-                />
-              </div>
-            </div>
+
             <div className="id">
               <div className="flex-start margin-bottom2">
-                <label className="flex25" htmlFor="id">
-                  아이디
-                </label>
-                <input
-                  type="text"
-                  name="id"
-                  placeholder=""
-                  autocomplete="off"
-                  id="id"
+                <label className="flex25" htmlFor="id"><span style={{color : "red"}}>*</span>아이디</label>
+                <input type="text"
+                  value={user['user_id']}
+                  onChange={(e) => {userValueChange('user_id', e.target.value); setIsIdCheck(false)}}
+                  ref={el => userRef.current['user_id'] = el}
                 />
-                <Button
-                  btnName={"중복확인"}
-                  className={"red-btn btn-large"}
-                  onclick="openIdChk()"
+                <button className={"red-btn btn-large"} onClick={userIdCheck}
+                  ref={el => userRef.current['user_id_check_button'] = el}>
+                  중복확인
+                </button>
+              </div>
+            </div>
+
+            <div>
+              <div className="flex-start margin-bottom2">
+                <label className="flex25" htmlFor="password"><span style={{color : "red"}}>*</span>비밀번호</label>
+                <input type="password"
+                  value={user['user_password']}
+                  onChange={(e) => {userValueChange('user_password', e.target.value)}}
+                  ref={el => userRef.current['user_password'] = el}
                 />
               </div>
             </div>
             <div>
               <div className="flex-start margin-bottom2">
-                <label className="flex25" htmlFor="password">
-                  비밀번호
-                </label>
-                <input
-                  type="text"
-                  name="password"
-                  placeholder=""
-                  autocomplete="off"
-                  id="password"
+                <label className="flex25" htmlFor="password_check"><span style={{color : "red"}}>*</span>비밀번호 확인</label>
+                <input type="password"
+                  value={user['user_password_check']}
+                  onChange={(e) => {userValueChange('user_password_check', e.target.value)}}
+                  ref={el => userRef.current['user_password_check'] = el}
                 />
               </div>
             </div>
-            <div>
-              <div className="flex-start margin-bottom2">
-                <label className="flex25" htmlFor="password_check">
-                  비밀번호 확인
-                </label>
-                <input
-                  type="text"
-                  name="password_check"
-                  placeholder=""
-                  autocomplete="off"
-                  id="password_check"
-                />
-              </div>
-            </div>
+
             <div>
               <div className="flex margin-bottom2">
-                <label className="flex25" htmlFor="phone_number">
-                  전화번호
-                </label>
-                <input
-                  type="text"
-                  name="phone_number"
-                  placeholder=""
-                  autocomplete="off"
-                  id="phone_number"
+                <label className="flex25" htmlFor="phone_number"><span style={{color : "red"}}>*</span>전화번호</label>
+                <input type="number" maxLength="11"
+                  value={user['user_phonenumber']}
+                  onChange={(e) => {userValueChange('user_phonenumber', e.target.value)}}
+                  ref={el => userRef.current['user_phonenumber'] = el}
                 />
               </div>
             </div>
-            <div className="btn-wrap">
-              <Button className={"gray-btn btn-large"} btnName={"취소"} />
-              <Button
-                className={"red-btn btn-large"}
-                btnName={"등록"}
-                onClick={() => {
-                  navigate("Login");
-                }}
-              />
+
+            <div>
+              <div className="flex-start margin-bottom2">
+                <label className="flex25" htmlFor="password_check">이메일</label>
+                <input type="text"
+                  value={user['user_email']}
+                  onChange={(e) => {userValueChange('user_email', e.target.value)}}
+                  ref={el => userRef.current['user_email'] = el}
+                />
+              </div>
             </div>
+
+            <div className="btn-wrap">
+              <button className={"gray-btn btn-large"} onClick={() => {navigate(-1)}}>취소</button>
+              <button className={"red-btn btn-large"} onClick={userInsert}>등록</button>
+            </div>
+
           </div>
         </div>
       </div>
client/views/pages/login/Login.jsx
--- client/views/pages/login/Login.jsx
+++ client/views/pages/login/Login.jsx
@@ -1,22 +1,57 @@
 import React from "react";
-import Button from "../../component/Button.jsx";
-import Join from "./../join/Join.jsx";
+import { useNavigate, useLocation } from "react-router";
 
-export default function Login({ getLogin }) {
-  const [isJoin, setIsJoin] = React.useState(false);
-  const onClickJoin = () => {
-    setIsJoin(true);
-    console.log(isJoin);
+
+import Join from "./../join/Join.jsx";
+import Button from "../../component/Button.jsx";
+
+
+export default function Login() {
+  const navigate = useNavigate();
+  const location = useLocation();
+
+  //로그인 정보
+  const [loginInfo, setLoginInfo] = React.useState({'user_id': '', 'user_password': ''});
+  //사용자의 입력으로 인한 로그인 정보 변경
+  const loginInfoChange = (key, value) => {
+    let newLoginInfo = JSON.parse(JSON.stringify(loginInfo));
+    newLoginInfo[key] = value;
+    setLoginInfo(newLoginInfo);
+  }
+
+  //로그인 엔터
+  const loginEnter = (key) => {
+    if (key == 'Enter') {
+      login();
+    } else {
+      return;
+    }
+  }
+
+  //로그인
+  const login = () => {
+    fetch("/user/login.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(loginInfo),
+    }).then((response) => response.json()).then((data) => {
+      console.log("로그인 결과 : ", data);
+      if (data.isSuccess == true) {
+        navigate('/Main');
+      } else {
+        alert(data.message);
+      }
+    }).catch((error) => {
+      console.log('login() /user/login.json error : ', error);
+    });
   };
-  const onClickLogin = () => {
-    getLogin();
-  };
+
   return (
     <div className="row login-wrap">
       <h1>시니어 스마트 케어 모니터링 플랫폼</h1>
-      {isJoin ? (
-        <Join />
-      ) : (
+      {location.pathname == '/Join' ? (<Join/>) : (
         <div className="container row flex-center join-login">
           <div className="login-form">
             <div>
@@ -24,19 +59,18 @@
               <div className="login-inner">
                 <div className="content">
                   <i className="fa-solid fa-user"></i>
-                  <input
-                    required
-                    maxlength="15"
-                    type="text"
-                    placeholder="아이디를 입력하세요"
+                  <input type="text" placeholder="아이디를 입력하세요"
+                    value={loginInfo['user_id']}
+                    onChange={(e) => {loginInfoChange('user_id', e.target.value)}}
+                    onKeyUp={(e) => {loginEnter(e.key)}}
                   />
                 </div>
                 <div className="content">
                   <i className="fa-solid fa-lock"></i>
-                  <input
-                    type="password"
-                    name="password"
-                    placeholder="비밀번호를 입력하세요"
+                  <input type="password" placeholder="비밀번호를 입력하세요"
+                    value={loginInfo['user_password']}
+                    onChange={(e) => {loginInfoChange('user_password', e.target.value)}}
+                    onKeyUp={(e) => {loginEnter(e.key)}}
                   />
                 </div>
               </div>
@@ -45,13 +79,13 @@
               <Button
                 className={"btn-100 green-btn"}
                 btnName={"로그인"}
-                onClick={onClickLogin}
+                onClick={login}
               />
               <div className="flex-center btn-bottom">
                 <Button
                   className={"join-btn"}
                   btnName={"회원가입"}
-                  onClick={onClickJoin}
+                  onClick={() => {navigate('/Join')}}
                 />
               </div>
             </div>
client/views/pages/user_management/UserAuthoriySelect.jsx
--- client/views/pages/user_management/UserAuthoriySelect.jsx
+++ client/views/pages/user_management/UserAuthoriySelect.jsx
@@ -1,5 +1,7 @@
 import React, { useState } from "react";
 import { useNavigate } from "react-router";
+import { useSelector } from "react-redux";
+
 import ContentTitle from "../../component/ContentTitle.jsx";
 import SubTitle from "../../component/SubTitle.jsx";
 import Modal from "../../component/Modal.jsx";
@@ -9,333 +11,634 @@
 import Modal_SeniorInsert from "../../component/Modal_SeniorInsert.jsx";
 import { width } from "@mui/system";
 import Modal_Guardian from "../../component/Modal_Guardian.jsx";
+import Pagination from "../../component/Pagination.jsx";
+
+import CommonUtil from "../../../resources/js/CommonUtil.js";
 
 export default function UserAuthoriySelect() {
   const navigate = useNavigate();
-  const [agencyName, setAgencyName] = useState("시행기관")
-  const [modalOpen, setModalOpen] = React.useState(false);
-  const openModal = () => {
-    setModalOpen(true);
-  };
-  const closeModal = () => {
-    setModalOpen(false);
-  };
-  const [modalOpen2, setModalOpen2] = React.useState(false);
-  const openModal2 = () => {
-    setModalOpen2(true);
-  };
-  const closeModal2 = () => {
-    setModalOpen2(false);
-  };
-  const thead = [
-    "No",
-    "소속기관명",
-    "이름",
-    "연락처",
-    "성별",
-    "주소",
-    "담당 대상자(어르신) 인원",
-  ];
-  const key = [
-    "No",
-    "center",
-    "name",
-    "phone",
-    "gender",
-    "address",
-    "worker",
-  ];
-  const content = [
-    {
-      No: 1,
-      center: "A복지관",
-      name: "홍길동",
-      phone: "010-1234-1234",
-      gender: "여",
-      address: "경상북도 군위군 삼국유사면",
-      worker: "10명"
-    },
 
-  ];
+  //전역 변수 저장 객체
+  const state = useSelector((state) => {return state});
 
-  const thead1 = [
-    "No",
-    "소속기관명", //관리기관 클릭시 보이게
-    "이름",
-    "대상자등록번호",
-    "생년월일",
-    "성별",
-    "연락처",
-    "주소",
-    "보호자",
-  ];
-  const key1 = ["No",
-    "name",
-    "center",
-    "management_number",
-    "birth",
-    "gender",
-    "phone",
-    "address",
-    "family",
-  ];
-  const content1 = [
-    {
-      No: 1,
-      center: "A복지관",
-      name: "김복남",
-      management_number: 2022080101,
-      birth: "1950.02.03",
-      gender: "남",
-      phone: "010-1234-1234",
-      address: "경상북도 군위군 삼국유사면",
-      family: (
-        <Button
-          className={"btn-small lightgray-btn"}
-          btnName={"보호자(가족) 보기"}
-          onClick={openModal}
-        />
-      ),
-    },
-  ];
-  const thead3 = [
-    "No",
-    "사용자명",
-    "사용자ID",
-    "대상자와의 관계",
-    "보호자 연락처",
-  ];
-  const key3 = [
-    "No",
-    "name",
-    "Id",
-    "relationship",
-    "phone",
-  ];
-  const content3 = [
-    {
-      No: 1,
-      name: "김훈",
-      Id: "admin2",
-      relationship: "아들",
-      phone: "010-1234-1234",
-    },
-  ];
-  const data = [
-    {
-      id: 1,
-      title: "대상자(사용자)",
-      description: (
-        <div>
-          <div className="search-management flex-start margin-bottom2">
-            <select>
-              <option value="이름">이름</option>
-              <option value="아이디">사용자등록번호</option>
-              <option value="아이디">ID</option>
-            </select>
-            <input type="text" />
-            <Button
-              className={"btn-small gray-btn"}
-              btnName={"검색"}
-              onClick={() => navigate("/SeniorInsert")}
-            />
-          </div>
-          <div className="btn-wrap flex-end margin-bottom">
-            <Button
-              className={"btn-small gray-btn"}
-              btnName={"등록"}
-              onClick={openModal2}
-            />
-            <Button className={"btn-small red-btn"} btnName={"삭제"} />
-          </div>
-          <Table
-            className={"protector-user"}
-            head={thead1}
-            contents={content1}
-            contentKey={key1}
-            onClick={() => {
-              navigate("/SeniorSelectOne");
-            }}
-          />
-        </div>
+  //활성화 탭 (시스템 업무 역할별)
+  const [tabActiveByRoleType, setTabActiveByRoleType] = React.useState('ROLE_SENIOR');
 
-      ),
-    },
-    {
-      id: 2,
-      title: "복지사(간호사)",
-      description: (
-        <div>
-          <div className="search-management flex-start margin-bottom2">
-            <select>
-              <option value="이름">이름</option>
-              <option value="아이디">사용자등록번호</option>
-              <option value="아이디">ID</option>
-            </select>
-            <input type="text" />
-            <Button
-              className={"btn-small gray-btn"}
-              btnName={"검색"}
-              onClick={() => navigate("/SeniorInsert")}
-            />
-          </div>
-          <div className="btn-wrap flex-end margin-bottom">
-            <Button
-              className={"btn-small gray-btn"}
-              btnName={"등록"}
-              onClick={() => {
-                navigate("/Join");
-              }}
-            />
-            <Button className={"btn-small red-btn"} btnName={"삭제"} />
-          </div>
-          <Table
-            className={"senior-table"}
-            head={thead}
-            contents={content}
-            contentKey={key}
-            onClick={() => {
-              navigate("/SeniorSelectOne");
-            }}
-          />
-        </div>
+  //보호자 모달 오픈 여부
+  const [modalGuardianIsOpen, setModalGuardianIsOpen] = React.useState(false);
+  //보호자 모달 오픈
+  const modalGuardianOpen = () => {
+    setModalGuardianIsOpen(true);
+  };
+  //보호자 모달 닫기
+  const modalGuardianClose = () => {
+    setModalGuardianIsOpen(false);
+  };
 
-      ),
-    },
-    {
-      id: 3,
-      title: "기관상세정보",
-      description: (
-        <div>
-          <table className="agency-detail">
-            <tbody>
-              <tr>
-                <td>회사명</td>
-                <td>군위군ㅊ청</td>
-              </tr>
-              <tr>
-                <td>주소</td>
-                <td>군위군 군위읍</td>
-              </tr>
-              <tr>
-                <td>담당직원</td>
-                <td>김직원</td>
-              </tr>
-              <tr>
-                <td>전화번호</td>
-                <td>053-855-8555</td>
-              </tr>
-            </tbody>
-          </table>
-        </div>
-      ),
-    },
-  ]
-  const [index, setIndex] = React.useState(1);
+  //대상자(시니어) 등록 모달 오픈 여부
+  const [modalSeniorInsertIsOpen, setModalSeniorInsertIsOpen] = React.useState(false);
+  //대상자(시니어) 등록 모달 오픈
+  const modalSeniorInsertOpen = () => {
+    setModalSeniorInsertIsOpen(true);
+  };
+  //대상자(시니어) 등록 모달 닫기
+  const modalSeniorInsertClose = () => {
+    setModalSeniorInsertIsOpen(false);
+  };
+
+  //기관 계층 구조 목록
+  const [orgListOfHierarchy, setOrgListOfHierarchy] = React.useState([]);
+  //기관(관리, 시행) 계층 구조 목록 조회
+  const orgSelectListOfHierarchy = () => {
+    fetch("/org/orgSelectListOfHierarchy.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify({}),
+    }).then((response) => response.json()).then((data) => {
+      console.log("기관(관리, 시행) 계층 구조 목록 조회 : ", data);
+      setOrgListOfHierarchy(data);
+    }).catch((error) => {
+      console.log('orgSelectListOfHierarchy() /org/orgSelectListOfHierarchy.json error : ', error);
+    });
+  };
+
+
+
+  //검색 변수 (초기화값)
+  const [userSearch, setUserSearch] = React.useState({
+    'government_id': state.loginUser['government_id'],
+    'agency_id': state.loginUser['agency_id'],
+    'authority': null,
+
+    'searchType': null,
+    'searchText': null,
+    'currentPage': 1,
+    'perPage': 10,
+  });
+
+  //대상자(시니어) 목록 및 페이징 정보
+  userSearch['authority'] = 'ROLE_SENIOR';
+  const [senior, setSenior] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))});
+  const seniorSearchChange = (targetKey, value) => {
+    let newSenior = JSON.parse(JSON.stringify(senior));
+    newSenior.search[targetKey] = value;
+    setSenior(newSenior);
+  }
+  const seniorSelectListEnter = (key) => {
+    if (key == 'Enter') {
+      seniorSelectList();
+    } else {
+      return;
+    }
+  }
+  //대상자(시니어) 목록 조회
+  const seniorSelectList = (currentPage) => {
+    senior.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage;
+
+    fetch("/user/userSelectList.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(senior.search),
+    }).then((response) => response.json()).then((data) => {
+      data.search = senior.search;
+      console.log("대상자(시니어) 목록 조회 : ", data);
+      setSenior(data);
+    }).catch((error) => {
+      console.log('seniorSelectList() /user/userSelectList.json error : ', error);
+    });
+  }
+
+  //시행기관 담당자 목록 및 페이징 정보
+  userSearch['authority'] = 'ROLE_AGENCY';
+  const [agent, setAgent] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))});
+  const agentSearchChange = (targetKey, value) => {
+    let newAgent = JSON.parse(JSON.stringify(agent));
+    newAgent.search[targetKey] = value;
+    setAgent(newAgent);
+  }
+  const agentSelectListEnter = (key) => {
+    if (key == 'Enter') {
+      agentSelectList();
+    } else {
+      return;
+    }
+  }
+  //시행기관 담당자 목록 조회
+  const agentSelectList = (currentPage) => {
+    agent.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage;
+
+    fetch("/user/userSelectList.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(agent.search),
+    }).then((response) => response.json()).then((data) => {
+      data.search = agent.search;
+      console.log("시행기관 담당자 목록 조회 : ", data);
+      setAgent(data);
+    }).catch((error) => {
+      console.log('agentSelectList() /user/userSelectList.json error : ', error);
+    });
+  }
+
+  //관리기관 관리자 목록 및 페이징 정보
+  userSearch['authority'] = 'ROLE_GOVERNMENT';
+  const [government, setGovernment] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))});
+  const governmentSearchChange = (targetKey, value) => {
+    let newGovernment = JSON.parse(JSON.stringify(government));
+    newGovernment.search[targetKey] = value;
+    setGovernment(newGovernment);
+  }
+  const governmentSelectListEnter = (key) => {
+    if (key == 'Enter') {
+      governmentSelectList();
+    } else {
+      return;
+    }
+  }
+  //관리기관 담당자 목록 조회
+  const governmentSelectList = (currentPage) => {
+    government.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage;
+
+    fetch("/user/userSelectList.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(government.search),
+    }).then((response) => response.json()).then((data) => {
+      data.search = government.search;
+      console.log("관리기관 담당자 목록 조회 : ", data);
+      setGovernment(data);
+    }).catch((error) => {
+      console.log('governmentSelectList() /user/userSelectList.json error : ', error);
+    });
+  }
+
+  //시스템 관리자 목록 및 페이징 정보
+  userSearch['authority'] = 'ROLE_ADMIN';
+  const [admin, setAdmin] = React.useState({userList: [], userListCount: 0, search: JSON.parse(JSON.stringify(userSearch))});
+  const adminSearchChange = (targetKey, value) => {
+    let newAdmin = JSON.parse(JSON.stringify(admin));
+    newAdmin.search[targetKey] = value;
+    setAdmin(newAdmin);
+  }
+  const adminSelectListEnter = (key) => {
+    if (key == 'Enter') {
+      adminSelectList();
+    } else {
+      return;
+    }
+  }
+  //시스템 관리자 목록 조회
+  const adminSelectList = (currentPage) => {
+    admin.search.currentPage = CommonUtil.isEmpty(currentPage) ? 1 : currentPage;
+
+    fetch("/user/userSelectList.json", {
+      method: "POST",
+      headers: {
+        'Content-Type': 'application/json; charset=UTF-8'
+      },
+      body: JSON.stringify(admin.search),
+    }).then((response) => response.json()).then((data) => {
+      data.search = admin.search;
+      console.log("시스템 관리자 목록 조회 : ", data);
+      setAdmin(data);
+    }).catch((error) => {
+      console.log('adminSelectList() /user/userSelectList.json error : ', error);
+    });
+  }
+
+
+  //올잇메디 선택
+  const adminChange = () => {
+    const newUserSearch = JSON.parse(JSON.stringify(userSearch));
+    newUserSearch['government_id'] = null;
+    newUserSearch['agency_id'] = null;
+    setUserSearch(newUserSearch);
+
+    senior.search['government_id'] = null;
+    senior.search['agency_id'] = null;
+    seniorSelectList();
+    agent.search['government_id'] = null;
+    agent.search['agency_id'] = null;
+    agentSelectList();
+    if (state.loginUser['authority'] == 'ROLE_ADMIN' || state.loginUser['authority'] == 'ROLE_GOVERNMENT') {
+      government.search['government_id'] = null;
+      government.search['agency_id'] = null;
+      governmentSelectList();
+    }
+  }
+
+  //관리 기관 선택
+  const governmentChange = (government_id) => {
+    const newUserSearch = JSON.parse(JSON.stringify(userSearch));
+    newUserSearch['government_id'] = government_id;
+    newUserSearch['agency_id'] = null;
+    setUserSearch(newUserSearch);
+
+    senior.search['government_id'] = government_id;
+    senior.search['agency_id'] = null;
+    seniorSelectList();
+    agent.search['government_id'] = government_id;
+    agent.search['agency_id'] = null;
+    agentSelectList();
+    if (state.loginUser['authority'] == 'ROLE_ADMIN' || state.loginUser['authority'] == 'ROLE_GOVERNMENT') {
+      government.search['government_id'] = government_id;
+      government.search['agency_id'] = null;
+      governmentSelectList();
+    }
+  }
+
+  //시행 기관 선택
+  const agencyChange = (government_id, agency_id) => {
+    const newUserSearch = JSON.parse(JSON.stringify(userSearch));
+    newUserSearch['government_id'] = government_id;
+    newUserSearch['agency_id'] = agency_id;
+    setUserSearch(newUserSearch);
+
+    senior.search['government_id'] = government_id;
+    senior.search['agency_id'] = agency_id;
+    console.log('senior.search : ', senior.search);
+    seniorSelectList();
+    agent.search['government_id'] = government_id;
+    agent.search['agency_id'] = agency_id;
+    agentSelectList();
+  }
+  
+  
+
+  //사용자 등록 페이지 이동
+  const join = () => {
+    console.log('userSearch : ', userSearch);
+    navigate("/Join", {state: {
+      'government_id': userSearch['government_id'],
+      'agency_id': userSearch['agency_id'],
+      'authority': tabActiveByRoleType,
+    }});
+  }
+
+
+  //Mounted
+  React.useEffect(() => {
+    orgSelectListOfHierarchy();
+    seniorSelectList();
+    agentSelectList();
+    if (state.loginUser['authority'] == 'ROLE_ADMIN' || state.loginUser['authority'] == 'ROLE_GOVERNMENT') {
+      governmentSelectList();
+    }
+    if (state.loginUser['authority'] == 'ROLE_ADMIN') {
+      adminSelectList();
+    }
+  }, []);
+
 
   return (
     <main>
-      <Modal_Guardian open={modalOpen} close={closeModal} header="'김복남'님의 가족">
-        <div className="board-wrap">
-          <SubTitle explanation={"최초 로그인 ID는 연락처, PW는 생년월일 8자리입니다."} className="margin-bottom" />
-          <table className="margin-bottom2 senior-insert">
-            <tr>
-              <th>이름</th>
-              <td>
-                <input type="text" />
-              </td>
-              <th>생년월일</th>
-              <td>
-                <div className="flex">
-                  <select name="year" id="year">
-                    <option value="">년</option>
-                  </select>
-                  <select name="month" id="month">
-                    <option value="">월</option>
-                  </select>
-                  <select name="days" id="days">
-                    <option value="">일</option>
-                  </select>
-                </div>
-              </td>
-            </tr>
-            <tr>
-              <th>연락처</th>
-              <td colSpan={3}>
-                <input type="input" maxLength="11" />
-              </td>
-            </tr>
-            <tr>
-              <th>대상자와의 관계</th>
-              <td colSpan={3}>
-                <input type="text" />
-              </td>
-            </tr>
-          </table>
-          <div className="btn-wrap flex-center margin-bottom5">
-            <Button
-              className={"btn-small red-btn"}
-              btnName={"추가"}
-              onClick={() => {
-                navigate("/SeniorInsert");
-              }}
-            />
-          </div>
-          <div>
-            <Table
-              className={"caregiver-user"}
-              head={thead3}
-              contents={content3}
-              contentKey={key3}
-            />
-          </div>
-        </div>
-      </Modal_Guardian>
-      <Modal_SeniorInsert open={modalOpen2} close={closeModal2} header="대상자(사용자) 등록" >
-      </Modal_SeniorInsert>
+      <Modal_Guardian open={modalGuardianIsOpen} close={modalGuardianClose}/>
+      <Modal_SeniorInsert
+        open={modalSeniorInsertIsOpen}
+        close={modalSeniorInsertClose}
+        seniorInsertCallback={() => {seniorSelectList(); modalSeniorInsertClose();}}
+        defaultAgencyId={userSearch['agency_id']}
+        defaultGovernmentId={userSearch['government_id']}
+      />
+
       <ContentTitle explanation={"사용자 관리"} />
       <div className="content-wrap">
-
-        <div
-          className="flex-align-start userauthoriylist"
-          style={{ height: "calc(100% - 61px)" }}
-        >
+        <div className="flex-align-start userauthoriylist" style={{ height: "calc(100% - 61px)" }}>
           <div className="left" style={{ height: "100%", }}>
             <div style={{ height: "100%" }}>
               <SubTitle
-                explanation={"관리기관 리스트"}
+                explanation={"기관 리스트"}
                 className="margin-bottom"
               />
-              <Category />
+              {/* 카테고리 디자인 필요 (a.active 클래스 필요) */}
+              <div style={{width: '100%', fontSize: '16px'}}>
+                {/* <a className={() => {return "active"}} onClick={adminChange}>올잇메디</a> */}
+                <a onClick={adminChange}
+                   className={userSearch['government_id'] == null && userSearch['agency_id'] == null ? "active" : ""}>
+                  올잇메디
+                </a>
+                <ul style={{marginLeft: '15px'}}>
+                  {orgListOfHierarchy.map((item, idx) => { return (
+                    <li style={{margin: '10px 0px'}} key={idx}>
+                      <span style={{marginRight: '5px'}}>└</span>
+                      <a onClick={() => {governmentChange(item['government_id'])}}
+                         className={item['government_id'] == userSearch['government_id'] ? "active" : ""}>
+                        {item['government_name']}
+                      </a>
+                      {item['agencyList'] != undefined && item['agencyList'] != null ?
+                        <ul style={{marginLeft: '15px'}}>
+                          {item['agencyList'].map((item2, idx2) => { return (
+                            <li style={{margin: '10px 0px'}} key={idx2}>
+                              <span style={{marginRight: '5px'}}>└</span>
+                              <a onClick={() => {agencyChange(item['government_id'], item2['agency_id'])}}
+                                 className={item2['agency_id'] == userSearch['agency_id'] ? "active" : ""}>
+                                {item2['agency_name']}
+                              </a>
+                            </li>
+                          )})}
+                        </ul>
+                        : null
+                      }
+                    </li>
+                  )})}
+                </ul>
+              </div>
+              {/* 카테고리 디자인 필요 */}
             </div>
           </div>
           <div className="right" style={{ height: "100%", }}>
             <div style={{ height: "100%" }}>
-              <SubTitle
-                explanation={`${agencyName} 사용자 리스트`}
-                className="margin-bottom"
-              />
+              <SubTitle explanation={`사용자 리스트`} className="margin-bottom"/>
               <div className="tab-container">
-                <ul className="tab-menu flex-end">
-                  {data.map((item) => (
-                    <li
-                      key={item.id}
-                      className={index === item.id ? "active" : null}
-                      onClick={() => setIndex(item.id)}
-                    >
-                      {item.title}
-                    </li>
-                  ))}
+
+                {/* 탭 제목 */}
+                <ul className="tab-menu flex-end" >
+                  <li onClick={() => setTabActiveByRoleType('ROLE_SENIOR')} className={tabActiveByRoleType == 'ROLE_SENIOR' ? "active" : null}>대상자(어르신) ({senior.userListCount})</li>
+                  <li onClick={() => setTabActiveByRoleType('ROLE_AGENCY')} className={tabActiveByRoleType == 'ROLE_AGENCY' ? "active" : null}>담당자 ({agent.userListCount})</li>
+                  <li onClick={() => setTabActiveByRoleType('ROLE_GOVERNMENT')} className={tabActiveByRoleType == 'ROLE_GOVERNMENT' ? "active" : null}>기관 관리자 ({government.userListCount})</li>
+                  <li onClick={() => setTabActiveByRoleType('ROLE_ADMIN')} className={tabActiveByRoleType == 'ROLE_ADMIN' ? "active" : null}>시스템 관리자 ({admin.userListCount})</li>
                 </ul>
+
+                {/* 탭 내용 */}
                 <div className="content-wrap userlist">
-                  <ul className="tab-content">
-                    {data
-                      .filter((item) => index === item.id)
-                      .map((item) => (
-                        <li>{item.description}</li>
-                      ))}
-                  </ul>
+                  {{
+                    /* 대상자(시니어) (시작) */
+                    ROLE_SENIOR: (
+                      <ul className="tab-content">
+                        <div>
+
+                          <div className="search-management flex-start margin-bottom2">
+                            <select id="searchType1" style={{maxWidth: 'fit-content'}} onChange={(e) => {seniorSearchChange("searchType", e.target.value)}}>
+                              <option value="" selected={senior.search.searchText == ""}>전체</option>
+                              <option value="user_name" selected={senior.search.searchText == "user_name"}>이름</option>
+                              <option value="user_phonenumber" selected={senior.search.searchText == "user_phonenumber"}>연락처</option>
+                              <option value="user_id" selected={senior.search.searchText == "user_id"}>아이디</option>
+                            </select>
+                            <input type="text" id="searchText1"
+                              value={senior.search.searchText}
+                              onChange={(e) => {seniorSearchChange("searchText", e.target.value)}}
+                              onKeyUp={(e) => {seniorSelectListEnter(e.key)}}
+                            />
+                            <button className={"btn-small gray-btn"} onClick={() => {seniorSelectList()}}>검색</button>
+                          </div>
+
+                          <div className="btn-wrap flex-end margin-bottom">
+                            <button className={"btn-small gray-btn"} onClick={() => modalSeniorInsertOpen()}>등록</button>
+                          </div>
+
+                          <table className={"protector-user"}>
+                            <thead>
+                              <tr>
+                                <th>No</th>
+                                <th>소속기관명</th>
+                                <th>이름</th>
+                                <th>생년월일</th>
+                                <th>성별</th>
+                                <th>연락처</th>
+                                <th>주소</th>
+                                
+                              </tr>
+                            </thead>
+                            <tbody>
+                              {senior.userList.map((item, idx) => { return (
+                                <tr key={idx} onClick={() => {navigate("/SeniorSelectOne")}}>
+                                  <td>{senior.userListCount - idx - (senior.search.currentPage - 1) * senior.search.perPage}</td>
+                                  <td>{item['agency_name']}</td>
+                                  <td>{item['user_name']}</td>
+                                  <td>{item['user_birth']}</td>
+                                  <td>{item['user_gender']}</td>
+                                  <td>{item['user_phonenumber']}</td>
+                                  <td>{item['user_address']}</td>
+                                </tr>
+                              )})}
+                              {senior.userList == null || senior.userList.length == 0 ?
+                                <tr>
+                                  <td colSpan={7}>조회된 데이터가 없습니다</td>
+                                </tr>  
+                              : null}
+                            </tbody>
+                          </table>
+                          <Pagination
+                            currentPage={senior.search.currentPage}
+                            perPage={senior.search.perPage}
+                            totalCount={senior.userListCount}
+                            maxRange={5}
+                            click={seniorSelectList}
+                          />
+                        </div>
+                      </ul>
+                    ),
+                    /* 대상자(시니어) (종료) */
+
+                    /* 시행기관(복지사, 간호사) 사용자 (시작) */
+                    ROLE_AGENCY: (
+                      <ul className="tab-content">
+                        <div>
+
+                          <div className="search-management flex-start margin-bottom2">
+                            <select id="searchType2"  style={{maxWidth: 'fit-content'}} onChange={(e) => {agentSearchChange("searchType", e.target.value)}}>
+                              <option value="" selected={agent.search.searchText == ""}>전체</option>
+                              <option value="user_name" selected={agent.search.searchText == "user_name"}>이름</option>
+                              <option value="user_phonenumber" selected={agent.search.searchText == "user_phonenumber"}>연락처</option>
+                              <option value="user_id" selected={agent.search.searchText == "user_id"}>아이디</option>
+                            </select>
+                            <input id="searchText2"  type="text"
+                              value={agent.search.searchText}
+                              onChange={(e) => {agentSearchChange("searchText", e.target.value)}}
+                              onKeyUp={(e) => {agentSelectListEnter(e.key)}}
+                            />
+                            <button className={"btn-small gray-btn"} onClick={() => {agentSelectList()}}>검색</button>
+                          </div>
+
+                          <div className="btn-wrap flex-end margin-bottom">
+                            <button className={"btn-small gray-btn"} onClick={join}>등록</button>
+                          </div>
+
+                          <table className={"senior-user"}>
+                            <thead>
+                              <tr>
+                                <th>No</th>
+                                <th>관리기관명</th>
+                                <th>소속기관명</th>
+                                <th>이름</th>
+                                <th>연락처</th>
+                                <th>이메일</th>
+                                <th>담당 대상자(어르신)</th>
+                                <th>가입승인</th>
+                              </tr>
+                            </thead>
+                            <tbody>
+                              {agent.userList.map((item, idx) => { return (
+                                <tr key={idx}>
+                                  <td>{agent.userListCount - idx - (agent.search.currentPage - 1) * agent.search.perPage}</td>
+                                  <td>{item['government_name']}</td>
+                                  <td>{item['agency_name']}</td>
+                                  <td>{item['user_name']}</td>
+                                  <td>{item['user_phonenumber']}</td>
+                                  <td>{item['user_email']}</td>
+                                  <td>
+                                    <button className={"btn-small lightgray-btn"} onClick={() => modalGuardianOpen()}>담당 대상자(어르신) 보기</button>
+                                  </td>
+                                  <td>
+                                    {item['is_accept'] ? "승인완료" : 
+                                      <button className={"btn-small red-btn"} onClick={() => {}}>가입승인</button>
+                                    }
+                                  </td>
+                                </tr>
+                              )})}
+                              {agent.userList == null || agent.userList.length == 0 ?
+                                <tr>
+                                  <td colSpan={8}>조회된 데이터가 없습니다</td>
+                                </tr>
+                              : null}
+                            </tbody>
+                          </table>
+                          <Pagination
+                            currentPage={agent.search.currentPage}
+                            perPage={agent.search.perPage}
+                            totalCount={agent.userListCount}
+                            maxRange={5}
+                            click={agentSelectList}
+                          />
+                        </div>
+                      </ul>
+                    ),
+                    /* 시행기관(복지사, 간호사) 사용자 (종료) */
+
+                    /* 관리기관(지자체, 병원) 사용자 (시작) */
+                    ROLE_GOVERNMENT: (
+                      <ul className="tab-content">
+                        <div>
+                          
+                          <div className="search-management flex-start margin-bottom2">
+                            <select style={{maxWidth: 'fit-content'}} onChange={(e) => {governmentSearchChange("searchType", e.target.value)}}>
+                              <option value="" selected={government.search.searchText == ""}>전체</option>
+                              <option value="user_name" selected={government.search.searchText == "user_name"}>이름</option>
+                              <option value="user_phonenumber" selected={government.search.searchText == "user_phonenumber"}>연락처</option>
+                              <option value="user_id" selected={government.search.searchText == "user_id"}>아이디</option>
+                            </select>
+                            <input type="text"
+                              value={government.search.searchText}
+                              onChange={(e) => {governmentSearchChange("searchText", e.target.value)}}
+                              onKeyUp={(e) => {governmentSelectListEnter(e.key)}}
+                            />
+                            <button className={"btn-small gray-btn"} onClick={() => {governmentSelectList()}}>검색</button>
+                          </div>
+
+                          <div className="btn-wrap flex-end margin-bottom">
+                            <button className={"btn-small gray-btn"} onClick={join}>등록</button>
+                          </div>
+
+                          <table className={"senior-user"}>
+                            <thead>
+                              <tr>
+                                <th>No</th>
+                                <th>소속기관명</th>
+                                <th>이름</th>
+                                <th>연락처</th>
+                                <th>이메일</th>
+                                <th>가입승인</th>
+                              </tr>
+                            </thead>
+                            <tbody>
+                              {government.userList.map((item, idx) => { return (
+                                <tr key={idx}>
+                                  <td>{government.userListCount - idx - (government.search.currentPage - 1) * government.search.perPage}</td>
+                                  <td>{item['government_name']}</td>
+                                  <td>{item['user_name']}</td>
+                                  <td>{item['user_phonenumber']}</td>
+                                  <td>{item['user_email']}</td>
+                                  <td>
+                                    {item['is_accept'] ? "승인완료" : 
+                                      <button className={"btn-small red-btn"} onClick={() => {}}>가입승인</button>
+                                    }
+                                  </td>
+                                </tr>
+                              )})}
+                              {government.userList == null || government.userList.length == 0 ?
+                                <tr>
+                                  <td colSpan={6}>조회된 데이터가 없습니다</td>
+                                </tr>
+                              : null}
+                            </tbody>
+                          </table>
+
+                        </div>
+                      </ul>
+                    ),
+                    /* 관리기관(지자체, 병원) 사용자 (종료) */
+
+                    /* 시스템 관리자 (시작) */
+                    ROLE_ADMIN: (
+                      <ul className="tab-content">
+                        <div>
+                          
+                          <div className="search-management flex-start margin-bottom2">
+                            <select style={{maxWidth: 'fit-content'}} onChange={(e) => {adminSearchChange("searchType", e.target.value)}}>
+                              <option value="" selected={admin.search.searchText == ""}>전체</option>
+                              <option value="user_name" selected={admin.search.searchText == "user_name"}>이름</option>
+                              <option value="user_phonenumber" selected={admin.search.searchText == "user_phonenumber"}>연락처</option>
+                              <option value="user_id" selected={admin.search.searchText == "user_id"}>아이디</option>
+                            </select>
+                            <input type="text"
+                              value={admin.search.searchText}
+                              onChange={(e) => {adminSearchChange("searchText", e.target.value)}}
+                              onKeyUp={(e) => {adminSelectListEnter(e.key)}}
+                            />
+                            <button className={"btn-small gray-btn"} onClick={() => {adminSelectList()}}>검색</button>
+                          </div>
+
+                          <div className="btn-wrap flex-end margin-bottom">
+                            <button className={"btn-small gray-btn"} onClick={join}>등록</button>
+                          </div>
+
+                          <table className={"senior-user"}>
+                            <thead>
+                              <tr>
+                                <th>No</th>
+                                <th>이름</th>
+                                <th>연락처</th>
+                                <th>이메일</th>
+                                <th>가입승인</th>
+                              </tr>
+                            </thead>
+                            <tbody>
+                              {admin.userList.map((item, idx) => { return (
+                                <tr key={idx}>
+                                  <td>{admin.userListCount - idx - (admin.search.currentPage - 1) * admin.search.perPage}</td>
+                                  <td>{item['user_name']}</td>
+                                  <td>{item['user_phonenumber']}</td>
+                                  <td>{item['user_email']}</td>
+                                  <td>
+                                    {item['is_accept'] ? "승인완료" : 
+                                      <button className={"btn-small red-btn"} onClick={() => {}}>가입승인</button>
+                                    }
+                                  </td>
+                                </tr>
+                              )})}
+                              {admin.userList == null || admin.userList.length == 0 ?
+                                <tr>
+                                  <td colSpan={5}>조회된 데이터가 없습니다</td>
+                                </tr>
+                              : null}
+                            </tbody>
+                          </table>
+
+                        </div>
+                      </ul>
+                    )
+                    /* 시스템 관리자 (종료) */
+                  }[tabActiveByRoleType]}
                 </div>
+
               </div>
             </div>
           </div>
node_modules/.package-lock.json
--- node_modules/.package-lock.json
+++ node_modules/.package-lock.json
@@ -1050,6 +1050,29 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
+    "node_modules/@reduxjs/toolkit": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz",
+      "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==",
+      "dependencies": {
+        "immer": "^9.0.16",
+        "redux": "^4.2.0",
+        "redux-thunk": "^2.4.2",
+        "reselect": "^4.1.7"
+      },
+      "peerDependencies": {
+        "react": "^16.9.0 || ^17.0.0 || ^18",
+        "react-redux": "^7.2.1 || ^8.0.2"
+      },
+      "peerDependenciesMeta": {
+        "react": {
+          "optional": true
+        },
+        "react-redux": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@types/d3": {
       "version": "7.4.0",
       "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz",
@@ -1321,6 +1344,15 @@
       "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz",
       "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA=="
     },
+    "node_modules/@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "dependencies": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
     "node_modules/@types/json-schema": {
       "version": "7.0.11",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -1381,6 +1413,11 @@
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
       "integrity": "sha512-3h04sJhF2rjOq8zUhyomORyKdr0RUts7FAz/JajBKGpTF0JSXjaj9fjWtAqj+pU1fwsGsHzcm3Neew3t/McUXA=="
+    },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
     },
     "node_modules/@webassemblyjs/ast": {
       "version": "1.11.1",
@@ -4727,6 +4764,15 @@
         "postcss": "^8.1.0"
       }
     },
+    "node_modules/immer": {
+      "version": "9.0.21",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/immer"
+      }
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -6462,6 +6508,44 @@
       "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
       "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
     },
+    "node_modules/react-redux": {
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
+      "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
+      "dependencies": {
+        "@babel/runtime": "^7.12.1",
+        "@types/hoist-non-react-statics": "^3.3.1",
+        "@types/use-sync-external-store": "^0.0.3",
+        "hoist-non-react-statics": "^3.3.2",
+        "react-is": "^18.0.0",
+        "use-sync-external-store": "^1.0.0"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8 || ^17.0 || ^18.0",
+        "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react": "^16.8 || ^17.0 || ^18.0",
+        "react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react-native": ">=0.59",
+        "redux": "^4"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        },
+        "react-dom": {
+          "optional": true
+        },
+        "react-native": {
+          "optional": true
+        },
+        "redux": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/react-resize-detector": {
       "version": "7.1.2",
       "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz",
@@ -6643,6 +6727,22 @@
       "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
       "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
     },
+    "node_modules/redux": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+      "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+      "dependencies": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
+    "node_modules/redux-thunk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+      "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+      "peerDependencies": {
+        "redux": "^4"
+      }
+    },
     "node_modules/regenerator-runtime": {
       "version": "0.13.11",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
@@ -6712,6 +6812,11 @@
       "engines": {
         "node": ">=0.10"
       }
+    },
+    "node_modules/reselect": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz",
+      "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A=="
     },
     "node_modules/resolve": {
       "version": "1.22.1",
@@ -8057,6 +8162,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/use-sync-external-store": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
package-lock.json
--- package-lock.json
+++ package-lock.json
@@ -16,6 +16,7 @@
         "@emotion/styled": "^11.10.5",
         "@mui/icons-material": "^5.11.0",
         "@mui/material": "^5.11.8",
+        "@reduxjs/toolkit": "^1.9.3",
         "add": "^2.0.6",
         "babel-loader": "^8.2.5",
         "chart.js": "^4.2.0",
@@ -27,7 +28,6 @@
         "file-loader": "^6.2.0",
         "fs": "0.0.1-security",
         "g3": "^0.2.37",
-        "history": "5.3.0",
         "moment": "^2.29.4",
         "mysql": "2.18.1",
         "oracledb": "5.5.0",
@@ -38,6 +38,7 @@
         "react-dom": "18.2.0",
         "react-is": "18.2.0",
         "react-kakao-maps-sdk": "^1.1.5",
+        "react-redux": "^8.0.5",
         "react-router": "6.3.0",
         "react-router-dom": "6.3.0",
         "recharts": "^2.1.16",
@@ -1099,6 +1100,29 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
+    "node_modules/@reduxjs/toolkit": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz",
+      "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==",
+      "dependencies": {
+        "immer": "^9.0.16",
+        "redux": "^4.2.0",
+        "redux-thunk": "^2.4.2",
+        "reselect": "^4.1.7"
+      },
+      "peerDependencies": {
+        "react": "^16.9.0 || ^17.0.0 || ^18",
+        "react-redux": "^7.2.1 || ^8.0.2"
+      },
+      "peerDependenciesMeta": {
+        "react": {
+          "optional": true
+        },
+        "react-redux": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@types/d3": {
       "version": "7.4.0",
       "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.0.tgz",
@@ -1370,6 +1394,15 @@
       "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz",
       "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA=="
     },
+    "node_modules/@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "dependencies": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
     "node_modules/@types/json-schema": {
       "version": "7.0.11",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -1430,6 +1463,11 @@
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/@types/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
       "integrity": "sha512-3h04sJhF2rjOq8zUhyomORyKdr0RUts7FAz/JajBKGpTF0JSXjaj9fjWtAqj+pU1fwsGsHzcm3Neew3t/McUXA=="
+    },
+    "node_modules/@types/use-sync-external-store": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
     },
     "node_modules/@webassemblyjs/ast": {
       "version": "1.11.1",
@@ -4822,6 +4860,15 @@
         "postcss": "^8.1.0"
       }
     },
+    "node_modules/immer": {
+      "version": "9.0.21",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/immer"
+      }
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -6563,6 +6610,44 @@
       "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
       "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
     },
+    "node_modules/react-redux": {
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
+      "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
+      "dependencies": {
+        "@babel/runtime": "^7.12.1",
+        "@types/hoist-non-react-statics": "^3.3.1",
+        "@types/use-sync-external-store": "^0.0.3",
+        "hoist-non-react-statics": "^3.3.2",
+        "react-is": "^18.0.0",
+        "use-sync-external-store": "^1.0.0"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8 || ^17.0 || ^18.0",
+        "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react": "^16.8 || ^17.0 || ^18.0",
+        "react-dom": "^16.8 || ^17.0 || ^18.0",
+        "react-native": ">=0.59",
+        "redux": "^4"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        },
+        "react-dom": {
+          "optional": true
+        },
+        "react-native": {
+          "optional": true
+        },
+        "redux": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/react-resize-detector": {
       "version": "7.1.2",
       "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-7.1.2.tgz",
@@ -6744,6 +6829,22 @@
       "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
       "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
     },
+    "node_modules/redux": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+      "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+      "dependencies": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
+    "node_modules/redux-thunk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+      "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+      "peerDependencies": {
+        "redux": "^4"
+      }
+    },
     "node_modules/regenerator-runtime": {
       "version": "0.13.11",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
@@ -6813,6 +6914,11 @@
       "engines": {
         "node": ">=0.10"
       }
+    },
+    "node_modules/reselect": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz",
+      "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A=="
     },
     "node_modules/resolve": {
       "version": "1.22.1",
@@ -8158,6 +8264,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/use-sync-external-store": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
package.json
--- package.json
+++ package.json
@@ -11,6 +11,7 @@
     "@emotion/styled": "^11.10.5",
     "@mui/icons-material": "^5.11.0",
     "@mui/material": "^5.11.8",
+    "@reduxjs/toolkit": "^1.9.3",
     "add": "^2.0.6",
     "babel-loader": "^8.2.5",
     "chart.js": "^4.2.0",
@@ -22,7 +23,6 @@
     "file-loader": "^6.2.0",
     "fs": "0.0.1-security",
     "g3": "^0.2.37",
-    "history": "5.3.0",
     "moment": "^2.29.4",
     "mysql": "2.18.1",
     "oracledb": "5.5.0",
@@ -33,6 +33,7 @@
     "react-dom": "18.2.0",
     "react-is": "18.2.0",
     "react-kakao-maps-sdk": "^1.1.5",
+    "react-redux": "^8.0.5",
     "react-router": "6.3.0",
     "react-router-dom": "6.3.0",
     "recharts": "^2.1.16",
Add a comment
List