첫 커밋
This commit is contained in:
18
src/entities/home/model/types.ts
Normal file
18
src/entities/home/model/types.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export interface FavoriteItemProps {
|
||||
img?: string,
|
||||
text?: string
|
||||
};
|
||||
export interface NoticeItemProps {
|
||||
title?: string,
|
||||
meta1?: string,
|
||||
meta2?: string,
|
||||
img?: string,
|
||||
};
|
||||
export interface HomeBottomBannerProps {
|
||||
setBottomBannerOn: (bottomBannerOn: boolean) => void;
|
||||
bottomBannerOn: boolean;
|
||||
};
|
||||
export interface AuthRegisterProps {
|
||||
setAuthRegisterOn: (authRegisterOn: boolean) => void;
|
||||
authRegisterOn: boolean;
|
||||
};
|
||||
74
src/entities/home/ui/auth-reguster.tsx
Normal file
74
src/entities/home/ui/auth-reguster.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { AuthRegisterProps } from '../model/types';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export const AuthRegister = ({
|
||||
setAuthRegisterOn,
|
||||
authRegisterOn,
|
||||
}: AuthRegisterProps) => {
|
||||
const { navigate } = useNavigate();
|
||||
|
||||
const onClickToClose = () => {
|
||||
setAuthRegisterOn(false);
|
||||
};
|
||||
const onClickToRegister = () => {
|
||||
// register
|
||||
};
|
||||
|
||||
const variants = {
|
||||
hidden: { y: '100%' },
|
||||
visible: { y: '0%' },
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{ (authRegisterOn) &&
|
||||
<div className="bg-dim"></div>
|
||||
}
|
||||
<motion.div
|
||||
className="bottomsheet"
|
||||
initial="hidden"
|
||||
animate={ (authRegisterOn)? 'visible': 'hidden' }
|
||||
variants={ variants }
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="bottomsheet-header">
|
||||
<div className="bottomsheet-title">
|
||||
<h2>간편 인증 등록</h2>
|
||||
<button
|
||||
className="close-btn"
|
||||
type="button"
|
||||
>
|
||||
<img
|
||||
src={ IMAGE_ROOT + '/ico_close.svg' }
|
||||
alt="닫기"
|
||||
onClick={ () => onClickToClose() }
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bottomsheet-content">
|
||||
<div className="text-section">
|
||||
<div>
|
||||
간편 인증 등록 한번으로,<br/>
|
||||
비밀번호 없이 편리하게 로그인하세요.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bottomsheet-footer">
|
||||
<button
|
||||
className="btn-50 btn-darkgray flex-1"
|
||||
type="button"
|
||||
onClick={ () => onClickToClose() }
|
||||
>다음에</button>
|
||||
<button
|
||||
className="btn-50 btn-blue flex-2"
|
||||
type="button"
|
||||
onClick={ () => onClickToRegister() }
|
||||
>지금 등록하기</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
44
src/entities/home/ui/day-status-box-container1.tsx
Normal file
44
src/entities/home/ui/day-status-box-container1.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
|
||||
export const BoxContainer1 = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="box-wrap">
|
||||
<h3>오늘 매출</h3>
|
||||
<div className="today-sales">
|
||||
<span className="won01">937,284,000원</span>
|
||||
<span className="per">↑ 43.6%</span>
|
||||
<a href="#" className="arrow">
|
||||
<img src={ IMAGE_ROOT + '/ico_arrow.svg' } alt="오늘 매출 바로가기" />
|
||||
</a>
|
||||
</div>
|
||||
<ul className="dales-detail">
|
||||
<li className="approve">승인 건수 <strong>8,277건</strong></li>
|
||||
<li className="cancel">취소 건수 <strong>320건</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="box-wrap">
|
||||
<h3>오늘 정산</h3>
|
||||
<div className="today-sales">
|
||||
<span className="won02">24,734,000원</span>
|
||||
<span className="per">입금완료</span>
|
||||
<a href="#" className="arrow">
|
||||
<img src={ IMAGE_ROOT + '/ico_arrow.svg' } alt="오늘 매출 바로가기" />
|
||||
</a>
|
||||
</div>
|
||||
<div className="progressbar">
|
||||
<div className="progress-header">
|
||||
<span className="progress-title">정산한도</span>
|
||||
<span className="progress-remaining">23% 남음</span>
|
||||
</div>
|
||||
<div className="progress-container">
|
||||
<div className="progress-bar">
|
||||
<div className="progress-fill" style={{width: '77%'}}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="remain-limit">잔여정산한도 <strong>7,833,000원</strong></div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
114
src/entities/home/ui/day-status-box-container2.tsx
Normal file
114
src/entities/home/ui/day-status-box-container2.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
|
||||
export const BoxContainer2 = () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<div className="section-header">
|
||||
<h3>매출/정산 현황</h3>
|
||||
<p>(전월 전체 매출/정산 대비 기준 )</p>
|
||||
</div>
|
||||
<div className="box-wrap two-sales">
|
||||
<h4>총 매출액</h4>
|
||||
<div className="today-sales mt-sty">
|
||||
<span className="won01">937,284,000원</span>
|
||||
<span className="per">↑ 43.6%</span>
|
||||
<a className="arrow">
|
||||
<img src={ IMAGE_ROOT + '/ico_arrow.svg' } alt="오늘 매출 바로가기" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="box-wrap two-sales">
|
||||
<h4>총 정산액</h4>
|
||||
<div className="today-sales mt-sty">
|
||||
<span className="won02">24,734,000원</span>
|
||||
<span className="per">↑ 26.8%</span>
|
||||
<a className="arrow">
|
||||
<img src={ IMAGE_ROOT + '/ico_arrow.svg' } alt="오늘 매출 바로가기" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="section-header">
|
||||
<h3>거래 인사이트</h3>
|
||||
<p>(최근 일주일 기준)</p>
|
||||
</div>
|
||||
<div className="box-wrap two-sales img-customer">
|
||||
<h4>평균 객단가</h4>
|
||||
<div className="two-account">
|
||||
<span>937,284,000원</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="box-wrap two-sales img-states">
|
||||
<h4>하루 평균 매출 및 건수</h4>
|
||||
<div className="two-account">
|
||||
<span>73,000,000원(1,800건)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="box-wrap ranking">
|
||||
<h4>매출이 가장 높은 요일</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<span className="ranking-num-01">1</span>
|
||||
<span>월요일 (354,342,000원)</span>
|
||||
<span className="last-per-01">30%</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="ranking-num-ot">2</span>
|
||||
<span>화요일 (63,983,000원)</span>
|
||||
<span className="last-per-ot">20%</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="ranking-num-ot">3</span>
|
||||
<span>수요일 (5,938,000원)</span>
|
||||
<span className="last-per-ot">10%</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="box-wrap ranking">
|
||||
<h4>매출이 가장 높은 시간</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<span className="ranking-num-01">1</span>
|
||||
<span>18시 (5,342,000원)</span>
|
||||
<span className="last-per-01">30%</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="ranking-num-ot">2</span>
|
||||
<span>10시 (994,000원)</span>
|
||||
<span className="last-per-ot">20%</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="ranking-num-ot">3</span>
|
||||
<span>23시 (478,000원)</span>
|
||||
<span className="last-per-ot">10%</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="box-wrap ranking">
|
||||
<h4>가장 많이쓰인 결제 수단</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<span className="ranking-num-01">1</span>
|
||||
<span>신용카드 (354,342,000원)</span>
|
||||
<span className="last-per-01">30%</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="ranking-num-ot">2</span>
|
||||
<span>가상계좌 (64,094,000원)</span>
|
||||
<span className="last-per-ot">20%</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="ranking-num-ot">3</span>
|
||||
<span>휴대폰 (478,000원)</span>
|
||||
<span className="last-per-ot">10%</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
50
src/entities/home/ui/day-status-box.tsx
Normal file
50
src/entities/home/ui/day-status-box.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { HomeNoticeList } from './home-notice-list';
|
||||
import { BoxContainer1 } from './day-status-box-container1';
|
||||
import { BoxContainer2 } from './day-status-box-container2';
|
||||
export const DayStatusBox = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="day-status">
|
||||
<div className="day-tab">
|
||||
<div>2025.06.16</div>
|
||||
<div>
|
||||
<button className="day-tab-btn active" data-target="one">일</button>
|
||||
<button className="day-tab-btn" data-target="two">월</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="con-box one active">
|
||||
{ <BoxContainer1></BoxContainer1> }
|
||||
</div>
|
||||
<div className="con-box two">
|
||||
{ <BoxContainer2></BoxContainer2> }
|
||||
</div>
|
||||
<div className="swiper-banner">
|
||||
<div className="banner-wrapper">
|
||||
<div className="banner-slide active">
|
||||
<div className="banner-content">
|
||||
<img src={ IMAGE_ROOT + '/home-banner01.png' } alt="배너 이미지" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="banner-slide">
|
||||
<div className="banner-content">
|
||||
<img src={ IMAGE_ROOT + '/home-banner01.png' } alt="배너 이미지" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="banner-slide">
|
||||
<div className="banner-content">
|
||||
<img src={ IMAGE_ROOT + '/home-banner01.png' } alt="배너 이미지" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="banner-pagination">
|
||||
<span className="banner-dot active" data-slide="0"></span>
|
||||
<span className="banner-dot" data-slide="1"></span>
|
||||
<span className="banner-dot" data-slide="2"></span>
|
||||
</div>
|
||||
</div>
|
||||
{ <HomeNoticeList></HomeNoticeList> }
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
17
src/entities/home/ui/favorite-item.tsx
Normal file
17
src/entities/home/ui/favorite-item.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { FavoriteItemProps } from '../model/types';
|
||||
|
||||
export const FavoriteItem = ({
|
||||
img,
|
||||
text
|
||||
}: FavoriteItemProps) => {
|
||||
return (
|
||||
<>
|
||||
<div className="swiper-item">
|
||||
<div className="swiper-icon coin-icon">
|
||||
<img src={ img } alt={ text } />
|
||||
</div>
|
||||
<span className="swiper-text">{ text }</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
60
src/entities/home/ui/favorite-wrapper.tsx
Normal file
60
src/entities/home/ui/favorite-wrapper.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||
import 'swiper/css';
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { FavoriteItem } from './favorite-item';
|
||||
import { FavoriteItemProps } from '../model/types'
|
||||
|
||||
|
||||
export const FavoriteWrapper = () => {
|
||||
const items: Array<FavoriteItemProps> = [
|
||||
{img: IMAGE_ROOT + '/ico_menu_01.svg', text: '지급대행'},
|
||||
{img: IMAGE_ROOT + '/ico_menu_02.svg', text: '거래내역조회'},
|
||||
{img: IMAGE_ROOT + '/ico_menu_03.svg', text: '정산달력'},
|
||||
{img: IMAGE_ROOT + '/ico_menu_02.svg', text: '거래내역조회'},
|
||||
{img: IMAGE_ROOT + '/ico_menu_03.svg', text: '정산달력'}
|
||||
];
|
||||
|
||||
const itemAdd = {
|
||||
img: IMAGE_ROOT + '/ico_menu_plus.svg',
|
||||
text: '편집하기'
|
||||
};
|
||||
|
||||
const getItems = () => {
|
||||
let rs = [];
|
||||
for(let i=0;i<items.length;i++){
|
||||
let img = items[i]?.img;
|
||||
let text = items[i]?.text;
|
||||
let key = 'slide-key-'+i;
|
||||
rs.push(
|
||||
<SwiperSlide
|
||||
key={ key }
|
||||
>
|
||||
<FavoriteItem
|
||||
img={ img }
|
||||
text={ text }
|
||||
></FavoriteItem>
|
||||
</SwiperSlide>
|
||||
);
|
||||
}
|
||||
|
||||
return rs;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Swiper
|
||||
spaceBetween={9}
|
||||
slidesPerView={4}
|
||||
onSlideChange={() => console.log('slide change')}
|
||||
>
|
||||
{ getItems() }
|
||||
<SwiperSlide>
|
||||
<FavoriteItem
|
||||
img={ itemAdd.img }
|
||||
text={ itemAdd.text }
|
||||
></FavoriteItem>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
61
src/entities/home/ui/home-bottom-banner.tsx
Normal file
61
src/entities/home/ui/home-bottom-banner.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import moment from 'moment';
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { StorageKeys } from '@/shared/constants/local-storage';
|
||||
import { setLocalStorage } from '@/shared/lib/web-view-bridge';
|
||||
import { HomeBottomBannerProps } from '../model/types';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export const HomeBottomBanner = ({
|
||||
setBottomBannerOn,
|
||||
bottomBannerOn
|
||||
}: HomeBottomBannerProps) => {
|
||||
const { navigate } = useNavigate();
|
||||
|
||||
const onClickToClose = () => {
|
||||
// close
|
||||
setBottomBannerOn(false);
|
||||
};
|
||||
const onClickToCloseDay = () => {
|
||||
// 오늘 날짜 기록
|
||||
const today = moment().format('YYYYMMDD');
|
||||
setLocalStorage(StorageKeys.BottomBannerClose, today);
|
||||
onClickToClose();
|
||||
};
|
||||
|
||||
const variants = {
|
||||
hidden: { y: '100%' },
|
||||
visible: { y: '0%' },
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{bottomBannerOn &&
|
||||
<div className="bg-dim"></div>
|
||||
}
|
||||
<motion.div
|
||||
className="bottomsheet banner"
|
||||
initial="hidden"
|
||||
animate={ (bottomBannerOn)? 'visible': 'hidden' }
|
||||
variants={ variants }
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="bottomsheet-content">
|
||||
<img
|
||||
src={ IMAGE_ROOT + '/sample_banner.png' }
|
||||
alt="배너"
|
||||
/>
|
||||
<div className="banner-page">
|
||||
<span className="current">1</span>
|
||||
/
|
||||
<span className="total">3</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bottom-btn">
|
||||
<span onClick={ () => onClickToCloseDay() }>오늘 하루 보지 않기</span>
|
||||
<span onClick={ () => onClickToClose() }>닫기</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
33
src/entities/home/ui/home-notice-item.tsx
Normal file
33
src/entities/home/ui/home-notice-item.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { NoticeItemProps } from '../model/types';
|
||||
|
||||
export const HomeNoticeItem = ({
|
||||
title,
|
||||
meta1,
|
||||
meta2,
|
||||
img
|
||||
}: NoticeItemProps) => {
|
||||
const { navigate } = useNavigate();
|
||||
|
||||
const onClickToNavigate = (path: string) => {
|
||||
navigate(path + '14');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="notice-item">
|
||||
<div className="notice-content">
|
||||
<div className="notice-title">{ title }</div>
|
||||
<div className="notice-meta">{ meta1}<span>{ meta2 }</span></div>
|
||||
</div>
|
||||
<div
|
||||
className="notice-arrow"
|
||||
onClick={ () => onClickToNavigate(PATHS.support.notice.detail) }
|
||||
>
|
||||
<img src={ img } alt="공지사항 바로가기" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
66
src/entities/home/ui/home-notice-list.tsx
Normal file
66
src/entities/home/ui/home-notice-list.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
/* eslint-disable @cspell/spellchecker */
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { HomeNoticeItem } from './home-notice-item';
|
||||
|
||||
export const HomeNoticeList = () => {
|
||||
const items = [
|
||||
{
|
||||
title: '시스템 안정화를 위한 정기 점검이 예정되어 있습니다.',
|
||||
meta1: '공지사항',
|
||||
meta2: '25년 5월 23일',
|
||||
img: IMAGE_ROOT + '/Forward.svg'
|
||||
},
|
||||
{
|
||||
title: '가맹점 관리 메뉴에 거래내역 엑셀 다운로드 기능이 추가 되었습니다.',
|
||||
meta1: '공지사항',
|
||||
meta2: '25년 5월 23일',
|
||||
img: IMAGE_ROOT + '/Forward.svg'
|
||||
},
|
||||
{
|
||||
title: '신규 가맹점을 대상으로 거래수수료 인하 혜택을 12월까지 제공합니다.',
|
||||
meta1: '공지사항',
|
||||
meta2: '25년 5월 23일',
|
||||
img: IMAGE_ROOT + '/Forward.svg'
|
||||
},
|
||||
{
|
||||
title: '앱의 안정성과 사용성을 개선한 버전 2.3.1이 출시되었습니다.',
|
||||
meta1: '공지사항',
|
||||
meta2: '25년 5월 23일',
|
||||
img: IMAGE_ROOT + '/Forward.svg'
|
||||
},
|
||||
{
|
||||
title: '점검 시간 동안 일부 서비스 이용이 제한될 수 있으니 미리 확인해주세요.',
|
||||
meta1: '공지사항',
|
||||
meta2: '25년 5월 23일',
|
||||
img: IMAGE_ROOT + '/Forward.svg'
|
||||
},
|
||||
];
|
||||
|
||||
const getItems = () => {
|
||||
let rs = [];
|
||||
for(let i=0;i<items.length;i++){
|
||||
let key = 'notice-key-'+i;
|
||||
rs.push(
|
||||
<HomeNoticeItem
|
||||
key={ key }
|
||||
title={ items[i]?.title }
|
||||
meta1={ items[i]?.meta1 }
|
||||
meta2={ items[i]?.meta2 }
|
||||
img={ items[i]?.img }
|
||||
></HomeNoticeItem>
|
||||
);
|
||||
}
|
||||
return rs;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="notice-list">
|
||||
<h3>공지 & 최신정보</h3>
|
||||
<div className="notice-box">
|
||||
{ getItems() }
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user