diff --git a/README.md b/README.md index 3d8a1d58..79e107f0 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,66 @@ -# React + Vite 프로젝트 초기 설정 +# 쉽게🎫티켓 -## Install dependencies +### 누구나 쉽게 배우는 티켓팅 플랫폼, 쉽게티켓😎 -``` -npm i -``` +![main](public/assets/images/main.png) + +## 프로젝트 소개 + +현재 다양한 이벤트, 공연, 스포츠 경기 등의 티켓 예매는 대부분 온라인에서 이루어지고 있습니다. 그러나 인터넷 사용에 익숙하지 않은 어르신분들 또는 사회적 약자들은 이러한 온라인 티켓팅에서 어려움을 겪고 있으며, 결과적으로 문화생활을 즐길 기회를 얻지 못하는 경우가 많습니다. + +쉽게티켓은 이러한 문제를 해결하고자 합니다. 사용자들이 티켓팅 과정을 연습하면서 다양한 난이도의 문제를 경험하여 실제 상황에서의 대응 능력을 기를 수 있도록 도와줍니다. 디지털 격차 없이 누구나 예매 과정을 쉽게 배울 수 있습니다. + +## 주요 기능 + +(ppt 사진으로 대체?) + +- 연습모드 + + - 다양한 난이도에 맞춰 티켓팅 연습을 할 수 있는 모드입니다. + - 사용자는 난이도에 따라 점진적으로 어려워지는 티켓팅 문제를 해결하며 예매 기술을 향상시킬 수 있습니다. + +- 실전모드 + - 실제 티켓팅과 유사한 화면을 구성하여, 제한 시간 내에 티켓팅에 성공하도록 유도하는 모드입니다. + - 실제 상황에서의 티켓팅 경험을 제공하여 실전 감각을 익힐 수 있습니다. + +## 팀 소개 -## Run +[팀 노션 바로가기](https://abyss-2.notion.site/ac49d8e6e597422ba111bc38594ba2f4?pvs=4) + +## 팀원 소개 + +| 고다은 | 이영주 | 이한희 | +| ------------------------------------------------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------ | +| ![profile1](https://avatars.githubusercontent.com/u/141714293?v=4) | ![profile2](https://avatars.githubusercontent.com/u/77565980?v=4) | ![profile3](https://avatars.githubusercontent.com/u/168459001?v=4) | +| [Daeun-100](https://github.com/Daeun-100) | [abyss-s](https://github.com/abyss-s) | [hanheel](https://github.com/hanheel) | +| FE | FE | FE | + +## 기술 스택 + +| 카테고리 | 스택 | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Environment | | +| Common | | +| Language | | +| Style | | +| Backend | | +| Collaboration | | + +## 기획 및 디자인 + +(피그마 링크 or 사진 첨부) + +### 플로우차트 + +### 와이어프레임 + +## 프로젝트 실행 ``` +npm i npm run dev ``` -## Lint and fix all +## 코멘트 -``` -npm run lint -``` +(각자 배운점, 아쉬운점 같은 부분 적기) diff --git a/public/assets/errorInfo.svg b/public/assets/errorInfo.svg new file mode 100644 index 00000000..5b4716e2 --- /dev/null +++ b/public/assets/errorInfo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/SeatCount.jsx b/src/components/SeatCount.jsx index 7484adc6..690ba7d1 100644 --- a/src/components/SeatCount.jsx +++ b/src/components/SeatCount.jsx @@ -59,7 +59,9 @@ const SeatCount = () => { const handleSeatCountChange = (event) => { setSeatCount(Number(event.target.value)); }; - + useEffect(() => { + setSeatCount(0); + }, []); useEffect(() => { if (seatCount === 0 && level === "low") { setFocus(true); diff --git a/src/components/card/settings/vertical/VerticalFront.jsx b/src/components/card/settings/vertical/VerticalFront.jsx index 3c0660b3..bcf2fd19 100644 --- a/src/components/card/settings/vertical/VerticalFront.jsx +++ b/src/components/card/settings/vertical/VerticalFront.jsx @@ -5,7 +5,7 @@ import { CardWrap, Number } from "../CardStyles"; const VerticalFront = () => { return ( - {/*카드 앞부분 */}s + {/*카드 앞부분 */} ); diff --git a/src/components/errorText/errorText.jsx b/src/components/errorText/errorText.jsx new file mode 100644 index 00000000..091fc392 --- /dev/null +++ b/src/components/errorText/errorText.jsx @@ -0,0 +1,25 @@ +import styled from "styled-components"; +import InfoIcon from "/public/assests/images/icons/errorInfo.svg?react"; + +const ErrorTextContainer = styled.div` + display: flex; + align-items: center; + gap: 8px; + height: 20px; +`; + +const ErrorTextMessage = styled.span` + color: var(--point-color); + font-size: 18px; +`; + +const ErrorText = ({ text }) => { + return ( + + + {text} + + ); +}; + +export default ErrorText; diff --git a/src/components/seatChart/SeatChart1.jsx b/src/components/seatChart/SeatChart1.jsx index 325f6051..781ec716 100644 --- a/src/components/seatChart/SeatChart1.jsx +++ b/src/components/seatChart/SeatChart1.jsx @@ -9,6 +9,12 @@ const SectionName = styled.div` font-family: "pretendardB"; margin: 20px; `; +const SeatChartContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +`; const SeatChart = () => { const allowedSection = useAtomValue(allowedSectionAtom); @@ -26,10 +32,10 @@ const SeatChart = () => { useFakeAllowedSeat(0, 9, 9); return ( - <> + {allowedSection}구역 - + ); }; diff --git a/src/components/seatInfo/SeatInfo.jsx b/src/components/seatInfo/SeatInfo.jsx index 80164ca1..40e3f71c 100644 --- a/src/components/seatInfo/SeatInfo.jsx +++ b/src/components/seatInfo/SeatInfo.jsx @@ -2,6 +2,7 @@ import Button from "../button/Button"; import { useAtomValue, useAtom } from "jotai"; import { isSeatSelectedAtom, + isSectionSelectedAtom, allowedSeatAtom, levelAtom, postersAtom, @@ -30,6 +31,7 @@ import { useLocation } from "react-router-dom"; const SeatInfo = () => { const isSeatSelected = useAtomValue(isSeatSelectedAtom); + const isSectionSelected = useAtomValue(isSectionSelectedAtom); const allowedSeat = useAtomValue(allowedSeatAtom); const level = useAtomValue(levelAtom); const posters = useAtomValue(postersAtom); @@ -61,18 +63,21 @@ const SeatInfo = () => { const nav = useNavigate(); const handleButtonClick = () => { - if (themeSite === "practice") { - nav("../step3-1"); - return; - } if (isSeatSelected) { if (path.includes("challenge")) { nav("../step3/step4"); - } else { - nav("../step3-1"); + return; } - } else { + nav("../step3-1"); + } + + if (!isSectionSelected) { + alert("구역을 선택해주세요."); + return; + } + if (!isSeatSelected) { alert("좌석을 선택해주세요."); + return; } }; diff --git a/src/hooks/useBookingValidate.js b/src/hooks/useBookingValidate.js index 4e6e3932..121a79ea 100644 --- a/src/hooks/useBookingValidate.js +++ b/src/hooks/useBookingValidate.js @@ -20,7 +20,7 @@ export const useBookingValidate = ( // 연습모드 // 좌석 매수가 0일 경우 경고창 출력 if (seatCount === 0) { - alert("좌석을 선택해주세요."); + alert("좌석매수를 선택해주세요."); return; } addStage(2); diff --git a/src/pages/ProgressContents.jsx b/src/pages/ProgressContents.jsx index 3ec1634f..64958bfe 100644 --- a/src/pages/ProgressContents.jsx +++ b/src/pages/ProgressContents.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import styled from "styled-components"; -import { useNavigate, useLocation, Outlet } from "react-router-dom"; +import { useLocation, Outlet } from "react-router-dom"; import { useAtom, useAtomValue, useSetAtom } from "jotai"; import Button from "../components/button/Button"; import Modal from "../components/modal/Modal"; @@ -75,19 +75,33 @@ const ProgressContents = ({ text, practiceMode, challengeMode }) => { useState(false); // 일시정지 모달창 제어 const [isPaused, setIsPaused] = useState(false); - - const path = useLocation().pathname; + const [isLoading, setIsLoading] = useState(true); + const location = useLocation(); + const path = location.pathname; // 현재 경로가 step0인지 확인하기 위한 변수 정의 - const isStep0Path = location.pathname.includes("step0"); + const isStep0Path = path.includes("step0"); // 시간이 초과되었을 때 타임아웃 모달 열리도록 설정 + useEffect(() => { + // 초기 로딩이 완료되면 로딩 상태를 false로 설정 + const timer = setTimeout(() => { + setIsLoading(false); + }, 100); // 0.1초 딜레이 + + return () => clearTimeout(timer); + }, []); + useEffect(() => { // 남은 시간 0 이하일 때만 모달이 열리도록 설정 - if (timeSpent <= 0 && !isStep0Path) { + if (isLoading) return; // 로딩 중일 때는 useEffect 실행하지 않음 + + if (isStep0Path) { + setIsTimeoutModalContentsOpen(false); + } else if (timeSpent <= 0 && level == "high") { setIsTimeoutModalContentsOpen(true); setTimerControl(false); // 타이머 정지 } - }, [timeSpent, setTimerControl]); + }, [timeSpent, isStep0Path, isLoading, setTimerControl]); const handleModalOpen = () => { setIsModalOpen(true); @@ -129,53 +143,61 @@ const ProgressContents = ({ text, practiceMode, challengeMode }) => { return ( {/*프로그래스 바*/} - - - - {/*고급 level일 경우에만 Timer 설정 */} - {/*모달이 열렸을 경우 Timer 정지 - isModalOpen, isPaused*/} - {level === "high" && themeSite === "practice" && } - {themeSite !== "practice" && } - {!path.includes("challenge") && {stepText}} - - {/*도움말 버튼 */} - {showHelpButton && ( - -