You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

355 lines
14 KiB

import useFadeIn from "../../hooks/useFadeIn";
import SubHero from "../../components/SubHero";
import { Fragment, useRef } from "react";
import { motion, useInView } from "framer-motion";
import { Search, Armchair, CalendarClock, Wallet, Ticket } from "lucide-react";
const ease = [0.22, 1, 0.36, 1];
function IbePage() {
const basePath = import.meta.env.BASE_URL;
const ref = useFadeIn();
const introRef = useRef(null);
const introInView = useInView(introRef, { once: true, margin: "-60px" });
const channelRef = useRef(null);
const channelInView = useInView(channelRef, { once: true, margin: "-60px" });
const bookingRef = useRef(null);
const bookingInView = useInView(bookingRef, { once: true, margin: "-60px" });
const SOLUTION_NAV = [
{ label: "비행상황관리 시스템", to: "/solution/flight-control" },
{ label: "IBE", to: "/solution/ibe" },
];
return (
<article ref={ref}>
<SubHero
label="SOLUTION"
title={
<>
<em>IBE</em>
</>
}
navItems={SOLUTION_NAV}
/>
<div className="sub-content">
<div className="inner-wrap">
{/* 개요 인트로 */}
<section className="fc-intro" ref={introRef}>
<div className="fc-intro__left">
<motion.span
className="fc-eyebrow"
initial={{ opacity: 0, y: 16 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
Overview
</motion.span>
<motion.h2
className="fc-intro__title"
initial={{ opacity: 0, y: 24 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.7, ease, delay: 0.1 }}
>
항공 예약의 모든 과정을
<br />
하나로 연결하는 통합 플랫폼
</motion.h2>
<motion.p
className="fc-intro__desc"
initial={{ opacity: 0, y: 16 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.2 }}
>
IBE(Internet Booking Engine) 항공권 검색부터 예약, 결제,
<br />
발권까지 모든 프로세스를 지원하는 차세대 예약 엔진 입니다.
<br />
다양한 채널과 시스템을 유연하게 연동하여 최적의 예약 경험을
제공합니다.
</motion.p>
<motion.div
className="fc-intro__icons"
initial={{ opacity: 0, y: 16 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.3 }}
>
{[
{ img: "ibe_intro_icon1.png", label: "다중 채널 연동" },
{ img: "ibe_intro_icon2.png", label: "실시간 예약/재고" },
{ img: "ibe_intro_icon3.png", label: "안정성과 확장성" },
{ img: "ibe_intro_icon4.png", label: "데이터 기반 운영" },
].map((item, i) => (
<div key={i} className="fc-intro__icon-item">
<img
src={`${basePath}images/${item.img}`}
alt={item.label}
/>
<span>{item.label}</span>
</div>
))}
</motion.div>
</div>
<motion.div
className="fc-intro__right"
initial={{ opacity: 0, x: 40 }}
animate={introInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.9, ease, delay: 0.15 }}
>
<img
src={`${basePath}images/ibe_computer.png`}
alt="IBE"
className="fc-intro__monitor"
/>
</motion.div>
</section>
{/* BOOKING PROCESS */}
<section className="ibe-booking-section" ref={bookingRef}>
<motion.span
className="fc-eyebrow"
initial={{ opacity: 0, y: 16 }}
animate={bookingInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
Booking Process
</motion.span>
<motion.h2
className="ibe-booking__title"
initial={{ opacity: 0, y: 24 }}
animate={bookingInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.7, ease, delay: 0.1 }}
>
직관적이고 간편한 예약 프로세스
</motion.h2>
<div className="ibe-booking__flow">
<svg width="0" height="0" style={{ position: "absolute" }}>
<defs>
<linearGradient
id="ibe-icon-grad"
x1="0%"
y1="0%"
x2="100%"
y2="100%"
>
<stop offset="0%" stopColor="#60a5fa" />
<stop offset="100%" stopColor="#f472b6" />
</linearGradient>
</defs>
</svg>
{[
{
num: "01",
icon: Search,
label: "검색",
desc: "출발지, 도착지, 일정,\n탑승객 정보를 입력하여\n최적의 항공편 검색",
},
{
num: "02",
icon: Armchair,
label: "선택",
desc: "운임, 스케줄, 좌석 등\n다양한 옵션을 비교하고\n원하는 항공편 선택",
},
{
num: "03",
icon: CalendarClock,
label: "예약",
desc: "승객 정보 입력 및\n부가 서비스 선택을 통해\n예약을 진행",
},
{
num: "04",
icon: Wallet,
label: "결제",
desc: "다양한 결제 수단을 지원하여\n안전하고 간편하게\n결제 진행",
},
{
num: "05",
icon: Ticket,
label: "발권",
desc: "E-Ticket 발행 후\n예약 정보를 확인하고\n예약 완료",
},
].map((item, i) => {
const Icon = item.icon;
return (
<Fragment key={i}>
<motion.div
className="ibe-booking__item"
initial={{ opacity: 0, y: 24 }}
animate={bookingInView ? { opacity: 1, y: 0 } : {}}
transition={{
duration: 0.6,
ease,
delay: 0.2 + i * 0.1,
}}
>
<div className="ibe-booking__circle">
<Icon
size={32}
strokeWidth={1.5}
stroke="url(#ibe-icon-grad)"
/>
</div>
<span className="ibe-booking__num">{item.num}</span>
<span className="ibe-booking__label">{item.label}</span>
<p className="ibe-booking__desc">
{item.desc.split("\n").map((line, j) => (
<span key={j}>
{line}
<br />
</span>
))}
</p>
</motion.div>
{i < 4 && (
<div
className="ibe-booking__connector"
style={{ "--delay": `${i * 0.4}s` }}
>
<div className="ibe-booking__line-bg" />
<div className="ibe-booking__line-flow" />
</div>
)}
</Fragment>
);
})}
</div>
</section>
{/* MULTI CHANNEL INTEGRATION */}
<section className="ibe-channel-section" ref={channelRef}>
<motion.span
className="fc-eyebrow"
initial={{ opacity: 0, y: 16 }}
animate={channelInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
Multi Channel Integration
</motion.span>
<motion.h2
className="ibe-channel__title"
initial={{ opacity: 0, y: 24 }}
animate={channelInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.7, ease, delay: 0.1 }}
>
다양한 시스템과의 유연한 연동
</motion.h2>
<motion.p
className="ibe-channel__desc"
initial={{ opacity: 0, y: 16 }}
animate={channelInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.2 }}
>
항공사 GDS, 호텔, 결제, 보험 다양한 외부 시스템과 API 기반
연동을 통해 확장성 높은 예약 환경을 제공합니다.
</motion.p>
<motion.div
className="ibe-channel__diagram"
initial={{ opacity: 0, y: 40 }}
animate={channelInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.8, ease, delay: 0.3 }}
>
<svg
className="ibe-channel__svg"
viewBox="0 0 1540 430"
preserveAspectRatio="none"
>
<path
className="ibe-channel__path"
d="M350 95 C520 95 560 185 710 185"
/>
<path
className="ibe-channel__path"
d="M350 215 C520 215 560 215 710 215"
/>
<path
className="ibe-channel__path"
d="M350 335 C520 335 560 245 710 245"
/>
<path
className="ibe-channel__path"
d="M830 185 C980 185 1020 95 1190 95"
/>
<path
className="ibe-channel__path"
d="M830 215 C980 215 1020 215 1190 215"
/>
<path
className="ibe-channel__path"
d="M830 245 C980 245 1020 335 1190 335"
/>
<circle cx="350" cy="95" r="4" className="ibe-channel__dot" />
<circle cx="350" cy="215" r="4" className="ibe-channel__dot" />
<circle cx="350" cy="335" r="4" className="ibe-channel__dot" />
<circle cx="1190" cy="95" r="4" className="ibe-channel__dot" />
<circle cx="1190" cy="215" r="4" className="ibe-channel__dot" />
<circle cx="1190" cy="335" r="4" className="ibe-channel__dot" />
</svg>
<div className="ibe-channel__cols-wrap">
<div className="ibe-channel__col ibe-channel__col--left">
{[
{ img: "ibe_pal_icon1.png", label: "항공사" },
{ img: "ibe_pal_icon2.png", label: "GDS" },
{ img: "ibe_pal_icon3.png", label: "호텔" },
].map((item, i) => (
<motion.div
key={i}
className="ibe-channel__card"
initial={{ opacity: 0, x: -24 }}
animate={channelInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.4 + i * 0.1 }}
>
<img
src={`${basePath}images/${item.img}`}
alt={item.label}
/>
<span>{item.label}</span>
</motion.div>
))}
</div>
<div className="ibe-channel__center">
<motion.img
src={`${basePath}images/ibe_pal_item.png`}
alt="PAL IBE"
className="ibe-channel__center-img"
initial={{ opacity: 0, scale: 0.8 }}
animate={channelInView ? { opacity: 1, scale: 1 } : {}}
transition={{ duration: 0.8, ease, delay: 0.5 }}
/>
</div>
<div className="ibe-channel__col ibe-channel__col--right">
{[
{ img: "ibe_pal_icon4.png", label: "결제 시스템" },
{ img: "ibe_pal_icon5.png", label: "여행사/OTA" },
{ img: "ibe_pal_icon6.png", label: "보험" },
].map((item, i) => (
<motion.div
key={i}
className="ibe-channel__card"
initial={{ opacity: 0, x: 24 }}
animate={channelInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.4 + i * 0.1 }}
>
<img
src={`${basePath}images/${item.img}`}
alt={item.label}
/>
<span>{item.label}</span>
</motion.div>
))}
</div>
</div>
</motion.div>
</section>
</div>
</div>
</article>
);
}
export default IbePage;