Skip to content

Commit

Permalink
#94 온보딩 페이지 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
cxaosdev committed Dec 2, 2024
1 parent a4e694e commit d81a442
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 3 deletions.
Binary file added public/assets/onboarding/editCalendar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import EventInfoModal from "/src/components/EventInfoModal";
import Header from "components/Header";
import LogIn from "/src/pages/LogIn";
import LoginPostCode from "/src/pages/LoginPostCode";
import OnBoarding from "/src/pages/OnBoarding";
import Profile from "/src/pages/Profile";
import ProfileEdit from "/src/pages/ProfileEdit";
import React from "react";
Expand All @@ -17,6 +18,7 @@ function Layout({ children }) {
<div>
<Routes>
<Route path="/login" element={null} />
<Route path="/" element={null} />
<Route
path="*"
element={
Expand All @@ -40,7 +42,8 @@ export default function App() {
<Routes>
<Route path="/login" element={<LogIn />} />
<Route path="/auth/*" element={<LoginPostCode />} />
<Route path="/" element={<Calendar />} />
<Route path="/" element={<OnBoarding />} />
<Route path="/calendar" element={<Calendar />} />
<Route path="/profile" element={<Profile />} />
<Route path="/profile/edit" element={<ProfileEdit />} />
<Route path="/event" element={<EventInfoModal />} />
Expand Down
Binary file added src/assets/onboarding/editCalendar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function Header() {
className="h-[2.5rem]"
src="/assets/evento_logo.png"
alt="Evento"
onClick={() => navigate("/")}
onClick={() => navigate("/calendar")}
/>
{!isLoggedIn ? (
<button
Expand Down
2 changes: 1 addition & 1 deletion src/pages/LoginPostCode.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function LoginPostCode() {
setUserInfo({ ...response.userInfo, token: response.token });

// 홈 화면으로 이동
navigate("/");
navigate("/calendar");
} catch (error) {
setErrorMessage("인증에 실패했습니다. 다시 시도해 주세요.");
console.error("Authentication error:", error);
Expand Down
172 changes: 172 additions & 0 deletions src/pages/OnBoarding.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

export default function OnBoarding() {
const navigate = useNavigate();
const [slides, setSlides] = useState([
{
show: true,
img: "/assets/evento_logo.png",
title: "간편한 일정 관리,",
body: "evento.와 함께 시작하세요",
},
{
show: false,
img: "/assets/onboarding/editCalendar.png",
title: "Evento1",
body: "이벤토이 이벤토이 벤토설이벤토 설명설 명설 명이벤 토이벤토",
},
{
show: false,
img: "/assets/onboarding/editCalendar.png",
title: "Evento2",
body: "이벤토이 이벤토이 벤토설이벤토 설명설 명설 명이벤 토이벤토",
},
{
show: false,
img: "/assets/onboarding/editCalendar.png",
title: "Evento3",
body: "이벤토이 이벤토이 벤토설이벤토 설명설 명설 명이벤 토이벤토",
},
{
show: false,
img: "/assets/onboarding/editCalendar.png",
title: "Evento4",
body: "이벤토이 이벤토이 벤토설이벤토 설명설 명설 명이벤 토이벤토",
},
{
show: false,
img: "/assets/onboarding/editCalendar.png",
title: "Evento5",
body: "이벤토이 이벤토이 벤토설이벤토 설명설 명설 명이벤 토이벤토",
},
{
show: false,
img: "/assets/evento_logo.png",
title: "지금 바로 시작하세요",
body: "",
},
]);
const [currentIndex, setCurrentIndex] = useState(0);
const [touchStart, setTouchStart] = useState({ x: 0, y: 0 });
const [touchEnd, setTouchEnd] = useState({ x: 0, y: 0 });

useEffect(() => {
const newSlides = slides.map((slide, index) => ({
...slide,
show: index === currentIndex,
}));
setSlides(newSlides);
}, [currentIndex]);

useEffect(() => {
const handleKeydown = (e) => {
if (e.key === "ArrowRight") {
setCurrentIndex((prevIndex) =>
Math.min(prevIndex + 1, slides.length - 1),
);
} else if (e.key === "ArrowLeft") {
setCurrentIndex((prevIndex) => Math.max(prevIndex - 1, 0));
}
};

window.addEventListener("keydown", handleKeydown);
return () => {
window.removeEventListener("keydown", handleKeydown);
};
}, [slides.length]);

const handleSwipe = () => {
const diffX = touchStart.x - touchEnd.x;

if (Math.abs(diffX) > 20) {
if (diffX > 0) {
setCurrentIndex((prevIndex) =>
Math.min(prevIndex + 1, slides.length - 1),
);
} else {
setCurrentIndex((prevIndex) => Math.max(prevIndex - 1, 0));
}
}
};

const handleDotClick = (index) => {
setCurrentIndex(index);
};

return (
<div className="min-w-screen flex min-h-screen items-center justify-center bg-eventoPurple/40 px-5 py-5">
<div className="mx-auto w-[40%] rounded-3xl px-10 pb-10 pt-16 text-eventoWhite">
{/* Carousel */}
<div className="relative mb-10 overflow-hidden">
<div
className="relative cursor-grab"
onTouchStart={(e) =>
setTouchStart({
x: e.touches[0].screenX,
y: e.touches[0].screenY,
})
}
onTouchEnd={(e) => {
setTouchEnd({
x: e.changedTouches[0].screenX,
y: e.changedTouches[0].screenY,
});
handleSwipe();
}}
>
{slides.map((slide, index) => (
<div
key={index}
className={`w-full text-center ${
slide.show ? "block" : "hidden"
}`}
>
<div
className="b-10 mx-auto h-72 w-72 border bg-center"
style={{
backgroundImage: `url(${slide.img})`,
backgroundSize: "contain",
backgroundRepeat: "no-repeat",
}}
></div>

<h2 className="mb-3 text-2xl font-bold text-eventoPurpleDark">
{slide.title}
</h2>
<p className="h-16 text-[1.2rem] font-medium leading-tight text-eventoWhite">
{slide.body}
</p>

{/* Get Started Button */}
{index === slides.length - 1 && (
<button
onClick={() => navigate("/login")}
className="mt-6 rounded-lg bg-eventoPurpleDark px-6 py-3 text-eventoWhite shadow hover:bg-eventoPurpleLight hover:text-eventoPurpleDark focus:outline-none active:bg-eventoPurple active:text-eventoWhite"
>
Get Started
</button>
)}
</div>
))}
</div>
</div>

{/* Dots */}
<div className="flex justify-center">
{slides.map((_, index) => (
<span
key={index}
onClick={() => handleDotClick(index)}
className={`mx-1 h-2 w-2 cursor-pointer rounded-full ${
index === currentIndex
? "bg-eventoWhite"
: "bg-eventoPurpleLight"
}`}
></span>
))}
</div>
</div>
</div>
);
}

0 comments on commit d81a442

Please sign in to comment.