From f7ab7be5a1dca2a7d5f65426f56f82a19ee8a558 Mon Sep 17 00:00:00 2001 From: osohyun0224 Date: Fri, 29 Sep 2023 17:01:51 +0900 Subject: [PATCH 1/8] =?UTF-8?q?Feat:=20=EB=B9=84=EB=8C=80=EB=A9=B4=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=20=EC=9D=98=EB=A3=8C=EC=A7=84=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84(=20=ED=95=B4=EB=8B=B9=20=ED=99=98=EC=9E=90=EC=9D=98?= =?UTF-8?q?=20=EC=9D=98=EB=A3=8C=EC=A7=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 2 + src/assets/icons/iconmajor.png | Bin 0 -> 3478 bytes .../UserDashBoard/UserDoReserve.jsx | 51 ++++++ .../UserDashBoard/UserSelectCard.jsx | 139 ++++++++++++++++ src/librarys/login-api.js | 154 ++++++++++-------- src/pages/User/UserReservePage.jsx | 34 ++++ 6 files changed, 308 insertions(+), 72 deletions(-) create mode 100644 src/assets/icons/iconmajor.png create mode 100644 src/components/UserDashBoard/UserDoReserve.jsx create mode 100644 src/components/UserDashBoard/UserSelectCard.jsx create mode 100644 src/pages/User/UserReservePage.jsx diff --git a/src/App.jsx b/src/App.jsx index a054aad..b70176c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,6 +4,7 @@ import SignupPage from "./pages/SignupPage.jsx"; import MyUserPage from './pages/User/MyUserPage.jsx'; import DevelopPage from './pages/DevelopPage.jsx'; import UserUntactReservePage from './pages/User/UserUntactReservePage.jsx'; +import UserReservePage from './pages/User/UserReservePage.jsx'; import styled from "styled-components"; import "./App.scss"; @@ -22,6 +23,7 @@ function App() { } /> }/> } /> + } /> diff --git a/src/assets/icons/iconmajor.png b/src/assets/icons/iconmajor.png new file mode 100644 index 0000000000000000000000000000000000000000..3d09d3075f10158678206149188e70f3bca96de1 GIT binary patch literal 3478 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 { + + return ( + + 비대면 진료 예약 + + 진료를 희망하는 의료진을 선택해주세요. + + + ); +}; + +export default UserDoReserve; \ No newline at end of file diff --git a/src/components/UserDashBoard/UserSelectCard.jsx b/src/components/UserDashBoard/UserSelectCard.jsx new file mode 100644 index 0000000..cfa2968 --- /dev/null +++ b/src/components/UserDashBoard/UserSelectCard.jsx @@ -0,0 +1,139 @@ +import { useState, useEffect } from 'react'; +import styled from 'styled-components'; +import Icondoctor from "../../assets/icons/icondoctor.png"; +import Iconmajor from "../../assets/icons/iconmajor.png"; +import Iconhospital from "../../assets/icons/iconhospital.png"; +import DoctorImage from "../../assets/images/user/Odoctor.png"; +import TherapistImage from "../../assets/images/user/Otherapist.png"; +import {userLogin} from "../../librarys/login-api"; + +const Card = styled.div` + width: 250px; + border: 1px solid #e1e1e1; + padding: 20px; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); + text-align: center; + margin: 20px; + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; + background-color: #ffffff; +`; + +const Title = styled.h1` + font-size: 14px; + margin-bottom: 15px; +`; + +const Separator = styled.hr` + width: 100%; + height: 2px; + background-color: #D9D9D9; + margin-bottom: 15px; + margin-top:10px; +`; + +const ImageContainer = styled.div` + width: 96px; + height: 96px; + border-radius: 50%; + margin: 0 auto; + margin-bottom: 20px; + overflow: hidden; +`; + +const Avatar = styled.img` + width: 100%; + height: 100%; +`; + +const UserName = styled.span` + font-size: 30px; + font-weight: bold; + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; +`; + +const UserTitle = styled.span` + font-size: 16px; + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; +`; + +const Info = styled.div` + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; + font-size: 12px; + margin-bottom: 10px; + text-align: left; +`; + +const Button = styled.button` + width: 150px; + height: 24px; + border-radius: 10px; + background-color: #000; + color: #fff; + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; + cursor: pointer; + border: none; + align-self: center; + margin-top: 15px; +`; + +const Icon = styled.img` + width: 16px; + height: 16px; + margin-right: 8px; + vertical-align: middle; +`; + +const UserSelectCard = () => { + const [userData, setUserData] = useState(null); + const [doctorData, setDoctorData] = useState(null); + const [therapistData, setTherapistData] = useState(null); + + useEffect(() => { + async function fetchUserData() { + const data = await userLogin('HL0001', '123456'); + if (data) { + setUserData(data); + + + const doctorDetails = await userLogin('doctor', '123456'); + setDoctorData(doctorDetails); + + + const therapistDetails = await userLogin('therapist', '123456'); + setTherapistData(therapistDetails); + } + } + fetchUserData(); + }, []); + + if (!userData) return null; + + return ( + + {userData.assignedDoctor ? "담당 전문의 프로필" : "담당 재활치료사 프로필"} + + + + + {userData.name} + + + + {userData.assignedDoctor ? "전문의" : "재활치료사"} + + + + {userData.assignedDoctor ? doctorData.workplace : therapistData.workplace} + + + + {userData.assignedDoctor ? doctorData.major : therapistData.major} + + + + + ); +} + +export default UserSelectCard; \ No newline at end of file diff --git a/src/librarys/login-api.js b/src/librarys/login-api.js index 845d23a..1f793da 100644 --- a/src/librarys/login-api.js +++ b/src/librarys/login-api.js @@ -1,87 +1,95 @@ export async function userLogin(id, password) { const accounts = [ - { - // User: 환자 - type: "user", - id: "HL0001", - password: "123456", - name: "오소현", - admin: false, - assignedDoctor: "김정원", // 배정된 전문의 - assignedTherapist: "오민혁", // 배정된 재활치료사 - recentVisitDate: "2023.09.01", // 최근 외래 진료일 - nextReservationDate: "2023.09.11" // 다음 외래 예약일 - }, - // Admin1: 전문의 - { - type: "admin1", - id: "doctor", - password: "123456", - name: "김정원", - admin: true, - }, - // Admin2: 재활치료사 - { - type: "admin2", - id: "therapist", - password: "123456", - name: "오민혁", - admin: true, - }, + { + // User: 환자 + type: "user", + id: "HL0001", + password: "123456", + name: "오소현", + admin: false, + assignedDoctor: "김정원", // 배정된 전문의 + assignedTherapist: "오민혁", // 배정된 재활치료사 + recentVisitDate: "2023.09.01", // 최근 외래 진료일 + nextReservationDate: "2023.09.11", // 다음 외래 예약일 + }, + // Admin1: 전문의 + { + type: "admin1", + id: "doctor", + password: "123456", + name: "김정원", + major: "재활의학과", + workplace: "한림대학교 춘천성심병원", + admin: true, + }, + // Admin2: 재활치료사 + { + type: "admin2", + id: "therapist", + password: "123456", + name: "오민혁", + major: "팔 재활", + workplace: "한림대학교 춘천성심병원 재활의료센터", + admin: true, + }, ]; const account = accounts.find((item) => item.id === id); if (!account || account.password !== password) { - return null; + return null; } // 계정 유형에 따른 다른 반환 값 switch (account.type) { - case "user": - return { - email: account.id, - name: account.name, - access_token: "user_token1", - refresh_token: "user_token2", - admin: account.admin, - assignedDoctor: account.assignedDoctor, - assignedTherapist: account.assignedTherapist, - recentVisitDate: account.recentVisitDate, - nextReservationDate: account.nextReservationDate - }; + case "user": + return { + email: account.id, + name: account.name, + access_token: "user_token1", + refresh_token: "user_token2", + admin: account.admin, + assignedDoctor: account.assignedDoctor, + assignedTherapist: account.assignedTherapist, + recentVisitDate: account.recentVisitDate, + nextReservationDate: account.nextReservationDate, + }; case "admin1": - return { - email: account.id, - name: account.name, - access_token: "admin1_token1", - refresh_token: "admin1_token2", - admin: account.admin, - }; + return { + email: account.id, + name: account.name, + major: account.major, + workplace: account.workplace, + access_token: "admin1_token1", + refresh_token: "admin1_token2", + admin: account.admin, + }; case "admin2": - return { - email: account.id, - name: account.name, - access_token: "admin2_token1", - refresh_token: "admin2_token2", - admin: account.admin, - }; - default: - return null; + return { + email: account.id, + name: account.name, + major: account.major, + workplace: account.workplace, + access_token: "admin2_token1", + refresh_token: "admin2_token2", + admin: account.admin, + }; + default: + return null; } } // 임시로 환자에게 할당된 과제 데이터를 추가 const userExercises = { - "HL0001": [ - { id: "1", name: "팔 운동 1", accuracy: "80%", judgement: "합격" }, - { id: "2", name: "팔 운동 2", accuracy: "80%", judgement: "합격" }, - { id: "3", name: "팔 운동 3", accuracy: "40%", judgement: "불합격" }, - { id: "4", name: "팔 운동 4", accuracy: "0%", judgement: "미수강" }, - { id: "5", name: "팔 운동 5", accuracy: "0%", judgement: "미수강" }, - { id: "6", name: "팔 운동 6", accuracy: "0%", judgement: "미수강" }, - { id: "7", name: "팔 운동 7", accuracy: "0%", judgement: "미수강" }, - { id: "8", name: "팔 운동 8", accuracy: "0%", judgement: "미수강" } - ] + HL0001: [ + { id: "1", name: "팔 운동 1", accuracy: "80%", judgement: "합격" }, + { id: "2", name: "팔 운동 2", accuracy: "80%", judgement: "합격" }, + { id: "3", name: "팔 운동 3", accuracy: "40%", judgement: "불합격" }, + { id: "4", name: "팔 운동 4", accuracy: "0%", judgement: "미수강" }, + { id: "5", name: "팔 운동 5", accuracy: "0%", judgement: "미수강" }, + { id: "6", name: "팔 운동 6", accuracy: "0%", judgement: "미수강" }, + { id: "7", name: "팔 운동 7", accuracy: "0%", judgement: "미수강" }, + { id: "8", name: "팔 운동 8", accuracy: "0%", judgement: "미수강" }, + ], }; // 환자의 ID를 입력받아 해당 환자에게 할당된 과제 데이터를 반환하는 함수 @@ -91,18 +99,20 @@ export function getUserExercises(userId) { // 기존 login-api.js 파일에 비대면 진료 기록 추가 const userUntactRecords = { - "HL0001": [ + HL0001: [ { date: "2023.08.31", doctorName: "김정원 전문의", - record: "환자는 3일 전부터 갑자기 시작된 기침과 가래를 주소로 내원하였음. 체온 측정 결과 38.2도로 발열 증상도 있음. 오늘 진료를 통해 급성 기관지염으로 진단하고, 관련 약물 처방하였음. 1주 후 재진을 권장함." + record: + "환자는 3일 전부터 갑자기 시작된 기침과 가래를 주소로 내원하였음. 체온 측정 결과 38.2도로 발열 증상도 있음. 오늘 진료를 통해 급성 기관지염으로 진단하고, 관련 약물 처방하였음. 1주 후 재진을 권장함.", }, { date: "2023.09.22", doctorName: "오민혁 재활치료사", - record: "환자는 3일 전부터 갑자기 시작된 기침과 가래를 주소로 내원하였음. 체온 측정 결과 38.2도로 발열 증상도 있음. 오늘 진료를 통해 급성 기관지염으로 진단하고, 관련 약물 처방하였음. 1주 후 재진을 권장함." - } - ] + record: + "환자는 3일 전부터 갑자기 시작된 기침과 가래를 주소로 내원하였음. 체온 측정 결과 38.2도로 발열 증상도 있음. 오늘 진료를 통해 급성 기관지염으로 진단하고, 관련 약물 처방하였음. 1주 후 재진을 권장함.", + }, + ], }; // 비대면 진료 기록을 반환하는 함수 diff --git a/src/pages/User/UserReservePage.jsx b/src/pages/User/UserReservePage.jsx new file mode 100644 index 0000000..393c74a --- /dev/null +++ b/src/pages/User/UserReservePage.jsx @@ -0,0 +1,34 @@ +import styled from 'styled-components'; +import Header from '../../components/Header/Header'; +import BackButton from "../../components/Button/BackButton"; +import UserDoReserve from '../../components/UserDashBoard/UserDoReserve'; + + +const PageContainer = styled.div` + display: flex; + flex-direction: column; + height: 100vh; +`; + +const CenteredContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; +`; + + +const UserReservePage = () => { + return ( + +
+ + + + + + ); +} + +export default UserReservePage; \ No newline at end of file From 473c21111853752c7a6365029b6b64f5859ff7dc Mon Sep 17 00:00:00 2001 From: osohyun0224 Date: Fri, 29 Sep 2023 17:24:15 +0900 Subject: [PATCH 2/8] =?UTF-8?q?Feat:=20=ED=99=98=EC=9E=90=20=EB=B9=84?= =?UTF-8?q?=EB=8C=80=EB=A9=B4=20=EC=A7=84=EB=A3=8C=20=EC=98=88=EC=95=BD=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84(=ED=99=98?= =?UTF-8?q?=EC=9E=90=EC=97=90=EA=B2=8C=20=EB=B0=B0=EC=A0=95=EB=90=9C=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UserDashBoard/UserDoReserve.jsx | 31 ++++- .../UserDashBoard/UserSelectCard.jsx | 114 ++++++++---------- src/librarys/login-api.js | 61 +++++----- 3 files changed, 109 insertions(+), 97 deletions(-) diff --git a/src/components/UserDashBoard/UserDoReserve.jsx b/src/components/UserDashBoard/UserDoReserve.jsx index 7d5b0f9..aa681ce 100644 --- a/src/components/UserDashBoard/UserDoReserve.jsx +++ b/src/components/UserDashBoard/UserDoReserve.jsx @@ -1,10 +1,12 @@ +import { useState, useEffect } from "react"; import styled from "styled-components"; -import UserSelectCard from "./UserSelectCard"; +import { UserSelectCard } from'./UserSelectCard'; +import { userLogin } from "../../librarys/login-api"; const Container = styled.div` width: 800px; - height: 885px; - margin: 0 auto; + height: 600px; + margin: 0 auto; padding: 20px; border: 1px solid #0064ff; border-radius: 10px; @@ -13,6 +15,13 @@ const Container = styled.div` position: relative; `; +const CardWrapper = styled.div` + display: flex; + justify-content: center; + margin-top: 20px; + gap: 30px; +`; + const Title = styled.h1` font-size: 28px; font-weight: bold; @@ -37,13 +46,27 @@ const Info = styled.p` ` const UserDoReserve = () => { + const [loginData, setLoginData] = useState(null); + + useEffect(() => { + const fetchLoginData = async () => { + const data = await userLogin('HL0001', '123456'); + setLoginData(data); + }; + fetchLoginData(); + }, []); + + if (!loginData) return null; return ( 비대면 진료 예약 진료를 희망하는 의료진을 선택해주세요. - + + + + ); }; diff --git a/src/components/UserDashBoard/UserSelectCard.jsx b/src/components/UserDashBoard/UserSelectCard.jsx index cfa2968..7fea9f5 100644 --- a/src/components/UserDashBoard/UserSelectCard.jsx +++ b/src/components/UserDashBoard/UserSelectCard.jsx @@ -1,14 +1,13 @@ -import { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; import styled from 'styled-components'; import Icondoctor from "../../assets/icons/icondoctor.png"; import Iconmajor from "../../assets/icons/iconmajor.png"; import Iconhospital from "../../assets/icons/iconhospital.png"; import DoctorImage from "../../assets/images/user/Odoctor.png"; import TherapistImage from "../../assets/images/user/Otherapist.png"; -import {userLogin} from "../../librarys/login-api"; const Card = styled.div` - width: 250px; + width: 280px; border: 1px solid #e1e1e1; padding: 20px; border-radius: 10px; @@ -52,10 +51,6 @@ const UserName = styled.span` font-family: 'Spoqa Han Sans Neo', 'sans-serif'; `; -const UserTitle = styled.span` - font-size: 16px; - font-family: 'Spoqa Han Sans Neo', 'sans-serif'; -`; const Info = styled.div` font-family: 'Spoqa Han Sans Neo', 'sans-serif'; @@ -65,75 +60,62 @@ const Info = styled.div` `; const Button = styled.button` - width: 150px; - height: 24px; - border-radius: 10px; - background-color: #000; - color: #fff; - font-family: 'Spoqa Han Sans Neo', 'sans-serif'; - cursor: pointer; - border: none; - align-self: center; - margin-top: 15px; + width: 150px; + height: 24px; + border-radius: 10px; + background-color: #3592FF; + color: #FEFDFD; + cursor: pointer; + border: none; + align-self: center; + font-size: 12px; `; const Icon = styled.img` - width: 16px; - height: 16px; - margin-right: 8px; - vertical-align: middle; + height: 12px; + width: 12px; + margin-right: 5px; + vertical-align: middle; +`; + +const MidSection = styled.div` + background-color: rgba(0, 100, 255, 0.03); `; -const UserSelectCard = () => { - const [userData, setUserData] = useState(null); - const [doctorData, setDoctorData] = useState(null); - const [therapistData, setTherapistData] = useState(null); - - useEffect(() => { - async function fetchUserData() { - const data = await userLogin('HL0001', '123456'); - if (data) { - setUserData(data); - - - const doctorDetails = await userLogin('doctor', '123456'); - setDoctorData(doctorDetails); - - - const therapistDetails = await userLogin('therapist', '123456'); - setTherapistData(therapistDetails); - } - } - fetchUserData(); - }, []); +export const UserSelectCard = ({ userType, userData }) => { if (!userData) return null; + const imageUrl = userType === "admin1" ? DoctorImage : TherapistImage; + const title = userType === "admin1" ? "담당 전문의 프로필" : "담당 재활치료사 프로필"; + return ( - - {userData.assignedDoctor ? "담당 전문의 프로필" : "담당 재활치료사 프로필"} - - - - - {userData.name} - - - - {userData.assignedDoctor ? "전문의" : "재활치료사"} - - - - {userData.assignedDoctor ? doctorData.workplace : therapistData.workplace} - - - - {userData.assignedDoctor ? doctorData.major : therapistData.major} - - - - + + {title} + + + + + + {userData.name} + + + {userType === "admin1" ? "전문의" : "재활치료사"} + {userData.workplace} + {userData.major} + + + ); } +UserSelectCard.propTypes = { + userType: PropTypes.string.isRequired, + userData: PropTypes.shape({ + name: PropTypes.string, + workplace: PropTypes.string, + major: PropTypes.string, + }).isRequired, +}; + export default UserSelectCard; \ No newline at end of file diff --git a/src/librarys/login-api.js b/src/librarys/login-api.js index 1f793da..9a9868f 100644 --- a/src/librarys/login-api.js +++ b/src/librarys/login-api.js @@ -35,14 +35,18 @@ export async function userLogin(id, password) { ]; const account = accounts.find((item) => item.id === id); + if (!account || account.password !== password) { return null; } - // 계정 유형에 따른 다른 반환 값 - switch (account.type) { - case "user": - return { + + if (account.type === "user") { + const doctor = accounts.find(item => item.name === account.assignedDoctor && item.type === "admin1"); + const therapist = accounts.find(item => item.name === account.assignedTherapist && item.type === "admin2"); + + return { + user: { email: account.id, name: account.name, access_token: "user_token1", @@ -52,30 +56,33 @@ export async function userLogin(id, password) { assignedTherapist: account.assignedTherapist, recentVisitDate: account.recentVisitDate, nextReservationDate: account.nextReservationDate, - }; - case "admin1": - return { - email: account.id, - name: account.name, - major: account.major, - workplace: account.workplace, - access_token: "admin1_token1", - refresh_token: "admin1_token2", - admin: account.admin, - }; - case "admin2": - return { - email: account.id, - name: account.name, - major: account.major, - workplace: account.workplace, - access_token: "admin2_token1", - refresh_token: "admin2_token2", - admin: account.admin, - }; - default: - return null; + }, + doctor, + therapist, + }; + } else if (account.type === "admin1") { + return { + email: account.id, + name: account.name, + major: account.major, + workplace: account.workplace, + access_token: "admin1_token1", + refresh_token: "admin1_token2", + admin: account.admin, + }; + } else if (account.type === "admin2") { + return { + email: account.id, + name: account.name, + major: account.major, + workplace: account.workplace, + access_token: "admin2_token1", + refresh_token: "admin2_token2", + admin: account.admin, + }; } + + return null; } // 임시로 환자에게 할당된 과제 데이터를 추가 From fd61abdd7beb573bb27521647cb3d4dac55531f1 Mon Sep 17 00:00:00 2001 From: osohyun0224 Date: Fri, 29 Sep 2023 18:09:43 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Feat:=20=EC=9D=98=EB=A3=8C=EC=A7=84=20?= =?UTF-8?q?=EB=B9=84=EB=8C=80=EB=A9=B4=20=EC=A7=84=EB=A3=8C=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=20=EB=AA=A8=EB=8B=AC=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=ED=8B=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 131 ++++++++++++++++++ package.json | 1 + src/assets/icons/iconx.png | Bin 0 -> 308 bytes .../UntactReserve/UntactReserveModal.jsx | 73 ++++++++++ .../UserDashBoard/UserSelectCard.jsx | 18 ++- 5 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 src/assets/icons/iconx.png create mode 100644 src/components/UntactReserve/UntactReserveModal.jsx diff --git a/package-lock.json b/package-lock.json index 857a003..a26dca2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "js-cookie": "^3.0.5", "prop-types": "^15.8.1", "react": "^18.2.0", + "react-calendar": "^4.6.0", "react-dom": "^18.2.0", "react-icons": "^4.10.1", "react-paginate": "^8.2.0", @@ -2744,6 +2745,19 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.199", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz", + "integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==" + }, + "node_modules/@types/lodash.memoize": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/lodash.memoize/-/lodash.memoize-4.1.7.tgz", + "integrity": "sha512-lGN7WeO4vO6sICVpf041Q7BX/9k1Y24Zo3FY0aUezr1QlKznpjzsDk3T3wvH8ofYzoK0QupN9TWcFAFZlyPwQQ==", + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/node": { "version": "14.18.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", @@ -3152,6 +3166,14 @@ "vite": "^4.2.0" } }, + "node_modules/@wojtekmaj/date-utils": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.5.0.tgz", + "integrity": "sha512-0mq88lCND6QiffnSDWp+TbOxzJSwy2V/3XN+HwWZ7S2n19QAgR5dy5hRVhlECXvQIq2r+VcblBu+S9V+yMcxXw==", + "funding": { + "url": "https://github.com/wojtekmaj/date-utils?sponsor=1" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -3701,6 +3723,14 @@ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, + "node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/code-block-writer": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz", @@ -5251,6 +5281,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-user-locale": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-2.3.0.tgz", + "integrity": "sha512-I3rQvAUwu2nauRD9YyQBSXVFJZixNouwA+eZld51Sn4Pn0N1qFbgcgOi/nPigJPQlNY519mT95fiSPRgflQiTA==", + "dependencies": { + "@types/lodash.memoize": "^4.1.7", + "lodash.memoize": "^4.1.1" + }, + "funding": { + "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5920,6 +5962,11 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6577,6 +6624,31 @@ "node": ">=0.10.0" } }, + "node_modules/react-calendar": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-4.6.0.tgz", + "integrity": "sha512-GJ6ZipKMQmlK666t+0hgmecu6WHydEnMWJjKdEkUxW6F471hiM5DkbWXkfr8wlAg9tc9feNCBhXw3SqsPOm01A==", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^2.0.0", + "get-user-locale": "^2.2.1", + "prop-types": "^15.6.0", + "tiny-warning": "^1.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -7334,6 +7406,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -9639,6 +9716,19 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "@types/lodash": { + "version": "4.14.199", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz", + "integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==" + }, + "@types/lodash.memoize": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/lodash.memoize/-/lodash.memoize-4.1.7.tgz", + "integrity": "sha512-lGN7WeO4vO6sICVpf041Q7BX/9k1Y24Zo3FY0aUezr1QlKznpjzsDk3T3wvH8ofYzoK0QupN9TWcFAFZlyPwQQ==", + "requires": { + "@types/lodash": "*" + } + }, "@types/node": { "version": "14.18.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", @@ -10016,6 +10106,11 @@ "react-refresh": "^0.14.0" } }, + "@wojtekmaj/date-utils": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.5.0.tgz", + "integrity": "sha512-0mq88lCND6QiffnSDWp+TbOxzJSwy2V/3XN+HwWZ7S2n19QAgR5dy5hRVhlECXvQIq2r+VcblBu+S9V+yMcxXw==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -10415,6 +10510,11 @@ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, + "clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + }, "code-block-writer": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-10.1.1.tgz", @@ -11487,6 +11587,15 @@ "get-intrinsic": "^1.1.1" } }, + "get-user-locale": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-2.3.0.tgz", + "integrity": "sha512-I3rQvAUwu2nauRD9YyQBSXVFJZixNouwA+eZld51Sn4Pn0N1qFbgcgOi/nPigJPQlNY519mT95fiSPRgflQiTA==", + "requires": { + "@types/lodash.memoize": "^4.1.7", + "lodash.memoize": "^4.1.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -11964,6 +12073,11 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -12415,6 +12529,18 @@ "loose-envify": "^1.1.0" } }, + "react-calendar": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-4.6.0.tgz", + "integrity": "sha512-GJ6ZipKMQmlK666t+0hgmecu6WHydEnMWJjKdEkUxW6F471hiM5DkbWXkfr8wlAg9tc9feNCBhXw3SqsPOm01A==", + "requires": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^2.0.0", + "get-user-locale": "^2.2.1", + "prop-types": "^15.6.0", + "tiny-warning": "^1.0.0" + } + }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -12941,6 +13067,11 @@ "convert-hrtime": "^3.0.0" } }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/package.json b/package.json index 85623eb..5b37bfc 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "js-cookie": "^3.0.5", "prop-types": "^15.8.1", "react": "^18.2.0", + "react-calendar": "^4.6.0", "react-dom": "^18.2.0", "react-icons": "^4.10.1", "react-paginate": "^8.2.0", diff --git a/src/assets/icons/iconx.png b/src/assets/icons/iconx.png new file mode 100644 index 0000000000000000000000000000000000000000..b694cb1a7da3d5bfcd9031e9c405b8b494def999 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|&H|6fVg?3oVGw3ym^DWND9BhG zmjV@L(#)GOV*Oo}{g5444MoNnD)(sY>f z3U7&Ag4kV#-?OhQaBno*`K00tw<_q;KYs70xm5kU?1qGc zKNzIt6;9mv_+WMiYt9BGgE`;-WgU#-kZw$Add<5c{McF}(IB~<1IcZL7PzwvLnw8g|}$#J)}j><0YQm&+%G<$q8nC0pw z5h=j?c#iPAiAjzkZ(8kkJ!F5S({$k8tE&}z7~|Hy*>l48xCYQu44$rjF6*2UngE*v BcHRI0 literal 0 HcmV?d00001 diff --git a/src/components/UntactReserve/UntactReserveModal.jsx b/src/components/UntactReserve/UntactReserveModal.jsx new file mode 100644 index 0000000..a5176ee --- /dev/null +++ b/src/components/UntactReserve/UntactReserveModal.jsx @@ -0,0 +1,73 @@ +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import XButton from '../../assets/icons/iconx.png'; + +const Overlay = styled.div` + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.4); + display: flex; + justify-content: center; + align-items: center; +`; + +const ModalContainer = styled.div` + width: 600px; + height: 600px; + background-color: #FFFFFF; + border-radius: 10px; + padding: 20px; + box-shadow: 0 0 15px rgba(0, 0, 0, 0.2); + position: relative; +`; + +const Title = styled.h1` + font-size: 28px; + font-weight: bold; + color: #333; + display: inline-block; +`; + +const CloseIcon = styled.img` + position: absolute; + right: 20px; + top: 20px; + cursor: pointer; + margin-top:10px; +`; + +const Divider = styled.hr` + width: 100%; + height: 1px; + background-color: #d9d9d9; + border: none; + margin-top: 10px; + margin-bottom: 20px; +`; + +const DateText = styled.p` + font-size: 16px; + margin-top: 10px; +`; + +export const UntactReserveModal = ({ onClose }) => { + return ( + + e.stopPropagation()}> + 예약 정보 작성 + + + 날짜 선택 * + + + ); +} + +UntactReserveModal.propTypes = { + onClose: PropTypes.func.isRequired, +}; + +export default UntactReserveModal; diff --git a/src/components/UserDashBoard/UserSelectCard.jsx b/src/components/UserDashBoard/UserSelectCard.jsx index 7fea9f5..cd192e2 100644 --- a/src/components/UserDashBoard/UserSelectCard.jsx +++ b/src/components/UserDashBoard/UserSelectCard.jsx @@ -1,3 +1,4 @@ +import { useState } from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import Icondoctor from "../../assets/icons/icondoctor.png"; @@ -5,6 +6,8 @@ import Iconmajor from "../../assets/icons/iconmajor.png"; import Iconhospital from "../../assets/icons/iconhospital.png"; import DoctorImage from "../../assets/images/user/Odoctor.png"; import TherapistImage from "../../assets/images/user/Otherapist.png"; +import { UntactReserveModal } from "../UntactReserve/UntactReserveModal"; + const Card = styled.div` width: 280px; @@ -84,13 +87,20 @@ const MidSection = styled.div` export const UserSelectCard = ({ userType, userData }) => { + const [isModalOpen, setIsModalOpen] = useState(false); + + const toggleModal = () => { + setIsModalOpen(!isModalOpen); + }; + if (!userData) return null; const imageUrl = userType === "admin1" ? DoctorImage : TherapistImage; const title = userType === "admin1" ? "담당 전문의 프로필" : "담당 재활치료사 프로필"; return ( - + <> + {title} @@ -104,8 +114,10 @@ export const UserSelectCard = ({ userType, userData }) => { {userData.workplace} {userData.major} - - + + + {isModalOpen && } + ); } From 2ed5e78a8e9d0330e9586a3e637652ada0d40f4b Mon Sep 17 00:00:00 2001 From: osohyun0224 Date: Fri, 29 Sep 2023 18:45:11 +0900 Subject: [PATCH 4/8] =?UTF-8?q?Feat:=20=EC=BA=98=EB=A6=B0=EB=8D=94=20?= =?UTF-8?q?=ED=95=9C=20=EB=B2=88=20=EC=8C=A9=EC=BD=94=EB=94=A9=20=ED=95=B4?= =?UTF-8?q?=EB=B3=B4=EC=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 11 ++ package.json | 1 + src/components/Calender/Calender.jsx | 33 ++++ src/components/Calender/CalenderItem.jsx | 36 ++++ src/components/Calender/CalenderStatus.jsx | 63 +++++++ src/components/Calender/Select.jsx | 173 ++++++++++++++++++ .../UntactReserve/UntactReserveModal.jsx | 2 + src/librarys/context.js | 4 + 8 files changed, 323 insertions(+) create mode 100644 src/components/Calender/Calender.jsx create mode 100644 src/components/Calender/CalenderItem.jsx create mode 100644 src/components/Calender/CalenderStatus.jsx create mode 100644 src/components/Calender/Select.jsx create mode 100644 src/librarys/context.js diff --git a/package-lock.json b/package-lock.json index a26dca2..04ce88e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@reduxjs/toolkit": "^1.9.5", "axios": "^1.5.0", "classnames": "^2.3.2", + "dayjs": "^1.11.10", "js-cookie": "^3.0.5", "prop-types": "^15.8.1", "react": "^18.2.0", @@ -3873,6 +3874,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -10632,6 +10638,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index 5b37bfc..b40f480 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@reduxjs/toolkit": "^1.9.5", "axios": "^1.5.0", "classnames": "^2.3.2", + "dayjs": "^1.11.10", "js-cookie": "^3.0.5", "prop-types": "^15.8.1", "react": "^18.2.0", diff --git a/src/components/Calender/Calender.jsx b/src/components/Calender/Calender.jsx new file mode 100644 index 0000000..108e4a8 --- /dev/null +++ b/src/components/Calender/Calender.jsx @@ -0,0 +1,33 @@ +import styled from "styled-components"; +import dayjs from "dayjs"; +import arraySupport from "dayjs/plugin/arraySupport"; +import CalenderItem from "./CalenderItem.jsx"; + +dayjs.extend(arraySupport); + +const Container = styled.div` + width: 100%; + margin-top: 23px; + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-gap: 6px; +`; + +const Calender = () => { + const current = dayjs(); + const year = current.year(); + const month = current.month(); + + const daysInMonth = dayjs([year, month + 1, 0]).date(); + const days = Array.from({ length: daysInMonth }, (_, i) => i + 1); + + return ( + + {days.map((day) => ( + + ))} + + ); +}; + +export default Calender; diff --git a/src/components/Calender/CalenderItem.jsx b/src/components/Calender/CalenderItem.jsx new file mode 100644 index 0000000..3da0c95 --- /dev/null +++ b/src/components/Calender/CalenderItem.jsx @@ -0,0 +1,36 @@ +import styled from 'styled-components'; +import PropTypes from 'prop-types'; + +const Container = styled.div` + width: 100%; + aspect-ratio: 1; + border-radius: 8px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + + &:hover { + background-color: #F3F1FF; + } +`; + +const Text = styled.p` + font-size: 16px; + font-weight: 700; +`; + +const CalenderItem = ({ date }) => { + return ( + + {date} + + ); +}; + +CalenderItem.propTypes = { + date: PropTypes.number.isRequired, +}; + +export default CalenderItem; diff --git a/src/components/Calender/CalenderStatus.jsx b/src/components/Calender/CalenderStatus.jsx new file mode 100644 index 0000000..4020913 --- /dev/null +++ b/src/components/Calender/CalenderStatus.jsx @@ -0,0 +1,63 @@ +import { useMemo, useContext } from "react"; +import { styled } from "styled-components"; + +import Select from "../Calender/Select.jsx" + +import { StateContext, DispatchContext } from "../../librarys/context.js"; +import { useState } from "react"; +import { useEffect } from "react"; + +const TotalAmount = styled.p` + font-size: 32px; + font-weight: 700; +`; + +const CalenderStatus = () => { + const { calenderlist, expenseList } = useContext(StateContext); + const dispatch = useContext(DispatchContext); + + const [value, setValue] = useState(); + const [list, setList] = useState([]); + + useEffect(() => { + if (!calenderlist) { + return; + } + const list = calenderlist.map((item, index) => ({ + id: index + 1, + year: item.year, + month: item.month, + name: `${item.year}년 ${item.month}월`, + })); + + setList(list); + + if (list[0]) { + setValue(list[0].id); + } + }, [calenderlist]); + + const price = useMemo( + () => expenseList.reduce((result, item) => result + item.price, 0), + [expenseList], + ); + + return ( + <> + { - setValue(item.id); - dispatch({ - type: "selectCalender", - payload: item, - }); - }} - /> - {price.toLocaleString()}원 - - ); -}; - -export default CalenderStatus; \ No newline at end of file diff --git a/src/components/Calender/Select.jsx b/src/components/Calender/Select.jsx deleted file mode 100644 index f8c4faa..0000000 --- a/src/components/Calender/Select.jsx +++ /dev/null @@ -1,173 +0,0 @@ -import PropTypes from "prop-types"; -import { useState, useEffect, useRef } from "react"; -import { styled } from "styled-components"; -import downArrowImage from "../../assets/icons/dropdownicon.png"; - -const Container = styled.div` - display: inline-block; -`; - -const SelectBox = styled.div` - border-radius: 6px; - display: flex; - align-items: center; - justify-content: space-between; - gap: 10px; - cursor: pointer; - - &.outline { - padding: 8px 12px; - border: 1px solid rgba(0, 0, 0, 0.25); - color: rgba(102, 112, 128, 1); - - &.focus { - outline: 2px solid black; - } - - & > p { - font-size: 16px; - font-weight: 500; - - @media screen and (max-width: 500px) { - font-size: 11px; - } - } - } -`; - -const Label = styled.p` - font-size: 20px; - font-weight: 700; -`; - -const Icon = styled.img` - width: 16px; - height: 16px; - object-fit: contain; - - @media screen and (max-width: 500px) { - width: 12px; - height: 12px; - } -`; - -const List = styled.div` - min-width: 120px; - max-height: 250px; - border: 1px solid #0000003f; - border-radius: 8px; - overflow: auto; - position: absolute; - z-index: 1; - background-color: white; - box-shadow: 0px 0px 8px #0000002f; - visibility: hidden; - - margin-top: 12px; - opacity: 0; - - transition: all 0.2s; - - &.visible { - margin-top: 4px; - opacity: 1; - visibility: visible; - } -`; - -const Item = styled.p` - padding: 8px; - font-size: 16px; - transition: background-color 0.1s; - cursor: pointer; - - @media screen and (max-width: 500px) { - padding: 6px 8px; - font-size: 12px; - } - - &.select { - background-color: #efefef; - } - - &:hover { - background-color: #dfdfdf; - } -`; - -const Select = ({ outline = false, list = [], value, onSelect, ...props }) => { - const [selectedItem, setItem] = useState(); - const [isVisible, setVisible] = useState(false); - const container = useRef(null); - - const eventCallback = (event) => { - if (container.current && !container.current.contains(event.target)) { - setVisible(false); - } - }; - - useEffect(() => { - document.addEventListener("click", eventCallback, true); - return () => { - document.removeEventListener("click", eventCallback, true); - }; - }, []); - - useEffect(() => { - if (value) { - const find = list.find((item) => item.id === value); - - if (find) { - setItem(find); - } - } - }, [value, list]); - - return ( - - setVisible(!isVisible)} - > - - - - - {list.map((item) => ( - (setItem(item), onSelect(item))} - > - {item.name} - - ))} - - - ); -}; - -Select.propTypes = { - /** 선택할 목록입니다. 목록의 각 항목에는 반드시 고유한 id가 부여되어야 합니다. */ - list: PropTypes.arrayOf( - PropTypes.shape({ - /** 항목의 id 입니다. id는 항목마다 고유한 값이어야만 합니다. */ - id: PropTypes.any.isRequired, - /** 항목의 이름입니다. 이 값이 화면에 표시되게 됩니다. */ - name: PropTypes.string, - /** 항목의 기본 값입니다. 이 값이 true면 맨 처음에 선택되어집니다. */ - default: PropTypes.bool, - }), - ), - className: PropTypes.string, - value: PropTypes.number, - outline: PropTypes.bool, - /** 목록에서 특정한 값이 선택되면 이 이벤트를 호출합니다. */ - onSelect: PropTypes.func, -}; - -export default Select; \ No newline at end of file diff --git a/src/components/UntactReserve/UntactReserveModal.jsx b/src/components/UntactReserve/UntactReserveModal.jsx index 23b76e1..7d74086 100644 --- a/src/components/UntactReserve/UntactReserveModal.jsx +++ b/src/components/UntactReserve/UntactReserveModal.jsx @@ -2,6 +2,7 @@ import styled from 'styled-components'; import PropTypes from 'prop-types'; import XButton from '../../assets/icons/iconx.png'; import Calendar from '../Calender/Calender.jsx'; +import { useState } from 'react'; const Overlay = styled.div` position: fixed; @@ -51,10 +52,46 @@ const Divider = styled.hr` const DateText = styled.p` font-size: 16px; - margin-top: 10px; + margin-top: -10px; +`; + +const TimeButton = styled.button` + width: 90px; + height: 40px; + border-radius: 10px; + border: ${({ status }) => (status === 'selected' ? '1px solid #0064FF' : '1px solid #E8E8E8')}; + background-color: ${({ status }) => (status === 'available' ? '#FAFAFA' : status === 'selected' ? '#F3F1FF' : '#888888')}; + color: ${({ status }) => (status === 'closed' ? '#444444' : '#000000')}; + cursor: ${({ status }) => (status === 'closed' ? 'not-allowed' : 'pointer')}; + margin-right: 5px; + + &:last-child { + margin-right: 0; + } +`; + +const TimeButtonContainer = styled.div` + display: flex; + margin-top: 20px; + margin-left:10px; + gap:10px; `; export const UntactReserveModal = ({ onClose }) => { + const [selectedTime, setSelectedTime] = useState(null); + + const times = [ + { label: "18:00", status: "available" }, + { label: "18:30", status: "available" }, + { label: "19:00", status: "available" }, + { label: "19:30", status: "closed" }, + { label: "20:00", status: "closed" }, + ]; + + const handleTimeSelect = (time) => { + setSelectedTime(time); + }; + return ( e.stopPropagation()}> @@ -63,6 +100,20 @@ export const UntactReserveModal = ({ onClose }) => { 날짜 선택 * + 시간 선택 * + + {times.map(time => ( + time.status === 'available' && handleTimeSelect(time.label)} + disabled={time.status === 'closed'} + > + {time.label} + + ))} + + 진료 희망 사유 * ); From 8e7cc4ef46b210ed19248fdfac29d3edd66febf4 Mon Sep 17 00:00:00 2001 From: osohyun0224 Date: Fri, 29 Sep 2023 20:27:12 +0900 Subject: [PATCH 8/8] =?UTF-8?q?Feat:=20=ED=99=98=EC=9E=90=EA=B0=80=20?= =?UTF-8?q?=EB=B9=84=EB=8C=80=EB=A9=B4=20=EC=A7=84=EB=A3=8C=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=ED=95=98=EB=8A=94=20=EB=AA=A8=EB=8B=AC=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Button/BackButton.jsx | 2 +- src/components/Input/InputTextLong.jsx | 34 +++++++++++++++++++ .../UntactReserve/UntactReserveModal.jsx | 31 +++++++++++++++-- 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/components/Input/InputTextLong.jsx diff --git a/src/components/Button/BackButton.jsx b/src/components/Button/BackButton.jsx index f03b392..54f2627 100644 --- a/src/components/Button/BackButton.jsx +++ b/src/components/Button/BackButton.jsx @@ -12,7 +12,7 @@ const BackButtonContainer = styled.button` align-items: center; justify-content: center; padding: 0 15px; - margin-top:60px; + margin-top:40px; margin-bottom: 10px; margin-left: -580px; `; diff --git a/src/components/Input/InputTextLong.jsx b/src/components/Input/InputTextLong.jsx new file mode 100644 index 0000000..9f713bf --- /dev/null +++ b/src/components/Input/InputTextLong.jsx @@ -0,0 +1,34 @@ +import styled from 'styled-components'; + +const InputContainer = styled.div` + display: flex; + flex-direction: column; + width: 320px; + margin-top:10px; +`; + + +const Input = styled.input` + width: 500px; + height: 100px; + border-radius: 10px; + background-color: #FAFAFA; + border: 1px solid #BBBBBB; + font-family: 'Spoqa Han Sans Neo', 'sans-serif'; + padding-left: 0px; + + &:focus { + outline: none; + } +`; + +function InputTextLong() { + return ( + + + + ); +} + +export { Input }; +export default InputTextLong; \ No newline at end of file diff --git a/src/components/UntactReserve/UntactReserveModal.jsx b/src/components/UntactReserve/UntactReserveModal.jsx index 7d74086..401a70b 100644 --- a/src/components/UntactReserve/UntactReserveModal.jsx +++ b/src/components/UntactReserve/UntactReserveModal.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import XButton from '../../assets/icons/iconx.png'; import Calendar from '../Calender/Calender.jsx'; import { useState } from 'react'; +import InputTextLong from '../Input/InputTextLong'; const Overlay = styled.div` position: fixed; @@ -55,6 +56,11 @@ const DateText = styled.p` margin-top: -10px; `; +const ReasonText = styled.p` + font-size: 16px; + margin-top: 10px; +`; + const TimeButton = styled.button` width: 90px; height: 40px; @@ -73,10 +79,27 @@ const TimeButton = styled.button` const TimeButtonContainer = styled.div` display: flex; margin-top: 20px; - margin-left:10px; - gap:10px; + margin-left:8px; + gap:5px; `; +const Button = styled.button` + width: 140px; + height: 30px; + background-color: #3592FF; + font-weight: 300; + color: #FEFDFD; + font-size: 14px; + border: none; + border-radius: 5px; + cursor: pointer; + margin-top:20px; + display: block; + margin-left: auto; + margin-right: auto; +`; + + export const UntactReserveModal = ({ onClose }) => { const [selectedTime, setSelectedTime] = useState(null); @@ -113,7 +136,9 @@ export const UntactReserveModal = ({ onClose }) => { ))} - 진료 희망 사유 * + 진료 희망 사유 * + + );