첫 커밋

This commit is contained in:
focp212@naver.com
2025-09-05 15:36:48 +09:00
commit 05238b04c1
825 changed files with 176358 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
export enum AccountTabKeys {
UserManage = 'UserManage',
PasswordManage = 'PasswordManage',
};
export interface AccountTabProps {
activeTab: AccountTabKeys;
};
export enum AccountUserTabKeys {
LoginAuthInfo = 'LoginAuthInfo',
AccountAuth = 'AccountAuth',
};
export interface AccountUserTabProps {
activeTab: AccountUserTabKeys;
tid: string;
};
export interface AuthItem {
useYn?: boolean;
authName?: string;
tid?: string;
};
export interface UserManageAuthListProps {
authItems: Array<AuthItem>
};
export interface UserManageAuthItemProps extends AuthItem {
};
export interface UserLoginAuthInfoWrapProps {
tid: string;
};
export interface UserAccountAuthWrapProps {
tid: string;
};
export interface PermItem {
menuId?: string;
permName?: string;
};
export interface UserAccountAuthPermListProps {
tid: string;
permItems: Array<PermItem>;
};
export interface UserAccountAuthPermItemProps extends PermItem {
tid: string;
};

View File

@@ -0,0 +1,37 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
AccountTabKeys,
AccountTabProps
} from '../model/types';
export const AccountTab = ({
activeTab
}: AccountTabProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = (tab: AccountTabKeys) => {
if(activeTab !== tab){
if(tab === AccountTabKeys.UserManage){
navigate(PATHS.account.user.manage);
}
else if(tab === AccountTabKeys.PasswordManage){
navigate(PATHS.account.password.manage);
}
}
};
return(
<>
<div className="subTab">
<button
className={`subtab-btn ${(activeTab === AccountTabKeys.UserManage)? 'active': ''}` }
onClick={ () => onClickToNavigation(AccountTabKeys.UserManage) }
> </button>
<button
className={`subtab-btn ${(activeTab === AccountTabKeys.PasswordManage)? 'active': ''}` }
onClick={ () => onClickToNavigation(AccountTabKeys.PasswordManage) }
> </button>
</div>
</>
);
};

View File

@@ -0,0 +1,46 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
AccountUserTabKeys,
AccountUserTabProps
} from '../model/types';
export const AccountUserTab = ({
activeTab,
tid
}: AccountUserTabProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = (tab: AccountUserTabKeys) => {
if(activeTab !== tab){
if(tab === AccountUserTabKeys.LoginAuthInfo){
navigate(PATHS.account.user.loginAuthInfo, {
state: {
tid: tid
}
});
}
else if(tab === AccountUserTabKeys.AccountAuth){
navigate(PATHS.account.user.accountAuth, {
state: {
tid: tid
}
});
}
}
};
return(
<>
<div className="subTab">
<button
className={`subtab-btn ${(activeTab === AccountUserTabKeys.LoginAuthInfo)? 'active': ''}` }
onClick={ () => onClickToNavigation(AccountUserTabKeys.LoginAuthInfo) }
> </button>
<button
className={`subtab-btn ${(activeTab === AccountUserTabKeys.AccountAuth)? 'active': ''}` }
onClick={ () => onClickToNavigation( AccountUserTabKeys.AccountAuth) }
></button>
</div>
</>
);
};

View File

@@ -0,0 +1,29 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
export const PasswordManageWrap = () => {
const { navigate } = useNavigate();
const onClickTonavigation = () => {
navigate(PATHS.account.password.modifyLoginPassword);
};
return (
<>
<div className="ing-list">
<div className="pwd-manage mt-20">
<div className="pwd-buttons">
<button
className="btn-44 btn-white pwd-btn"
type="button"
onClick={ () => onClickTonavigation() }
> </button>
<button
className="btn-44 btn-white pwd-btn"
type="button"
> </button>
</div>
</div>
</div>
</>
)
};

View File

@@ -0,0 +1,31 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { UserAccountAuthPermItemProps } from '../model/types';
export const UserAccountAuthPermItem = ({
tid,
menuId,
permName
}: UserAccountAuthPermItemProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = () => {
navigate(PATHS.account.user.menuAuth, {
state: {
tid: tid,
menuId: menuId
}
})
};
return (
<>
<div
className="perm-item"
onClick={ () => onClickToNavigation() }
>
<span className="perm-name">{ permName }</span>
<span className="ic20 arrow-right"></span>
</div>
</>
);
};

View File

@@ -0,0 +1,30 @@
import { UserAccountAuthPermListProps } from '../model/types';
import { UserAccountAuthPermItem } from './user-account-auth-perm-item';
export const UserAccountAuthPermList = ({
tid,
permItems
}: UserAccountAuthPermListProps) => {
const getPermItems = () => {
let rs = [];
for(let i=0;i<permItems.length;i++){
rs.push(
<UserAccountAuthPermItem
key={ 'key-perm-item-' + i }
tid={ tid }
menuId={ permItems[i]?.menuId }
permName={ permItems[i]?.permName }
></UserAccountAuthPermItem>
);
}
return rs;
};
return (
<>
<div className="perm-list">
{ getPermItems() }
</div>
</>
);
};

View File

@@ -0,0 +1,58 @@
import { UserAccountAuthWrapProps } from '../model/types';
import { UserAccountAuthPermList } from './user-account-auth-perm-list';
export const UserAccountAuthWrap = ({
tid
}: UserAccountAuthWrapProps) => {
let menuItems = [
{menuId: 'menu1', permName: '거래조회'},
{menuId: 'menu2', permName: '정산조회'},
{menuId: 'menu3', permName: '가맹점 관리'},
{menuId: 'menu4', permName: '결제 관리'},
{menuId: 'menu5', permName: '계정 관리'},
{menuId: 'menu6', permName: '부가세 신고 자료'},
{menuId: 'menu7', permName: '부가서비스'},
{menuId: 'menu8', permName: '고객지원'},
];
return (
<>
<div className="ing-list pdtop">
<div className="perm-form">
<div className="perm-field">
<div className="perm-label"> </div>
<div className="perm-control">
<select>
<option selected></option>
<option></option>
</select>
</div>
</div>
<div className="perm-field">
<div className="perm-label"> </div>
<div className="perm-control">
<select>
<option>MID</option>
<option>GID</option>
<option selected>MID + GID</option>
</select>
</div>
</div>
</div>
<div className="ing-title fs18"> </div>
<UserAccountAuthPermList
tid={ tid }
permItems={ menuItems }
></UserAccountAuthPermList>
<div className="apply-row bottom-padding">
<button
className="btn-50 btn-blue flex-1"
type="button"
></button>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,100 @@
import { UserLoginAuthInfoWrapProps } from '../model/types';
export const UserLoginAuthInfoWrap = ({
tid
}: UserLoginAuthInfoWrapProps) => {
return (
<>
<div className="ing-list pdtop">
<div className="settings-login-auth">
<div className="group">
<div className="group-header">
<div className="title"> </div>
<button
className="ic20 plus"
type="button"
aria-label="추가"
></button>
</div>
<div className="input-row">
<input
type="text"
value="nicetest01@nicepay.co.kr"
placeholder="example@domain.com"
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
></button>
</div>
<div className="input-row">
<input
type="text"
value="nicetest01@nicepay.co.kr"
placeholder="example@domain.com"
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
></button>
</div>
<div className="input-row">
<input
type="text"
placeholder="example@domain.com"
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
></button>
</div>
</div>
<div className="group">
<div className="group-header">
<div className="title"> </div>
<button
className="ic20 plus"
type="button"
aria-label="추가"
></button>
</div>
<div className="input-row">
<input
type="text"
value="01012345678"
placeholder="휴대폰 번호 입력"
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
></button>
</div>
<div className="input-row">
<input
type="text"
value="01012345678"
placeholder="휴대폰 번호 입력"
readOnly={ true }
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
></button>
</div>
<div className="notice-bar"> .</div>
</div>
</div>
<div className="apply-row bottom-padding">
<button className="btn-50 btn-blue flex-1"></button>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,33 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { UserManageAuthItemProps } from '../model/types';
export const UserManageAuthItem = ({
useYn,
authName,
tid
}: UserManageAuthItemProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = () => {
navigate(PATHS.account.user.loginAuthInfo, {
state: {
tid: tid
}
});
};
return (
<>
<div
className="auth-item"
onClick={ () => onClickToNavigation() }
>
<div className="auth-item-left">
<span className={ `tag-pill ${(!!useYn)? '': 'red'}` }>{ (!!useYn)? '사용': '미사용' }</span>
<span className="auth-name">{ authName }</span>
</div>
<span className="ic20 arrow-right"></span>
</div>
</>
);
};

View File

@@ -0,0 +1,29 @@
import { UserManageAuthItem } from './user-manage-auth-item';
import { UserManageAuthListProps } from '../model/types';
export const UserManageAuthList = ({
authItems
}: UserManageAuthListProps) => {
const getUserManageAuthItems = () => {
let rs = [];
for(let i=0;i<authItems.length;i++){
rs.push(
<UserManageAuthItem
key={ 'UserManageAuthItem-key-' + i }
useYn={ authItems[i]?.useYn }
authName= { authItems[i]?.authName }
tid= { authItems[i]?.tid }
></UserManageAuthItem>
);
}
return rs;
}
return (
<>
<div className="auth-list">
{ getUserManageAuthItems() }
</div>
</>
);
};

View File

@@ -0,0 +1,53 @@
import { useEffect, useState } from 'react';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { AuthItem } from '../model/types';
import { UserManageAuthList } from './user-manage-auth-list';
export const UserManageWrap = () => {
const { navigate } = useNavigate();
const [authItems, setAuthItems] = useState<Array<AuthItem>>([]);
const callAuthList = () => {
setAuthItems([
{useYn: true, authName: 'test01', tid: 'A12334556'},
{useYn: true, authName: 'test02', tid: 'A33334556'},
{useYn: true, authName: 'test03', tid: 'A12345556'},
{useYn: true, authName: 'test04', tid: 'A12978676'},
{useYn: false, authName: 'test05', tid: 'A12344444'},
]);
};
const onClickToNavigation = () => {
navigate(PATHS.account.user.addAccount);
};
useEffect(() => {
callAuthList();
}, []);
return (
<>
<div className="ing-list">
<div className="input-wrapper top-select mt-16">
<select>
<option>nicetest00m</option>
</select>
</div>
<div className="ing-title"> </div>
{ (!!authItems && authItems.length > 0) &&
<UserManageAuthList
authItems={ authItems }
></UserManageAuthList>
}
<div className="apply-row bottom-padding">
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigation() }
> </button>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionAlimtalkDetailParams,
ExtensionAlimtalkDetailResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionAlimtalkDetail = (params: ExtensionAlimtalkDetailParams) => {
return resultify(
axios.post<ExtensionAlimtalkDetailResponse>(API_URL.extensionArsDetail(), params),
);
};
export const useExtensionAlimtalkDetailMutation = (options?: UseMutationOptions<ExtensionAlimtalkDetailResponse, CBDCAxiosError, ExtensionAlimtalkDetailParams>) => {
const mutation = useMutation<ExtensionAlimtalkDetailResponse, CBDCAxiosError, ExtensionAlimtalkDetailParams>({
...options,
mutationFn: (params: ExtensionAlimtalkDetailParams) => extensionAlimtalkDetail(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionAlimtalkDownloadExcelParams,
ExtensionAlimtalkDownloadExcelResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionAlimtalkDownloadExcel = (params: ExtensionAlimtalkDownloadExcelParams) => {
return resultify(
axios.post<ExtensionAlimtalkDownloadExcelResponse>(API_URL.extensionAlimtalkDownloadExcel(), params),
);
};
export const useExtensionAlimtalkDownloadExcelMutation = (options?: UseMutationOptions<ExtensionAlimtalkDownloadExcelResponse, CBDCAxiosError, ExtensionAlimtalkDownloadExcelParams>) => {
const mutation = useMutation<ExtensionAlimtalkDownloadExcelResponse, CBDCAxiosError, ExtensionAlimtalkDownloadExcelParams>({
...options,
mutationFn: (params: ExtensionAlimtalkDownloadExcelParams) => extensionAlimtalkDownloadExcel(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionAlimtalkListParams,
ExtensionAlimtalkListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionAlimtalkList = (params: ExtensionAlimtalkListParams) => {
return resultify(
axios.post<ExtensionAlimtalkListResponse>(API_URL.extensionAlimtalkList(), params),
);
};
export const useExtensionAlimtalkListMutation = (options?: UseMutationOptions<ExtensionAlimtalkListResponse, CBDCAxiosError, ExtensionAlimtalkListParams>) => {
const mutation = useMutation<ExtensionAlimtalkListResponse, CBDCAxiosError, ExtensionAlimtalkListParams>({
...options,
mutationFn: (params: ExtensionAlimtalkListParams) => extensionAlimtalkList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionAlimtalkSettingDetailParams,
ExtensionAlimtalkSettingDetailResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionAlimtalkSettingDetail = (params: ExtensionAlimtalkSettingDetailParams) => {
return resultify(
axios.post<ExtensionAlimtalkSettingDetailResponse>(API_URL.extensionAlimtalkSettingDetail(), params),
);
};
export const useExtensionAlimtalkSettingSaveMutation = (options?: UseMutationOptions<ExtensionAlimtalkSettingDetailResponse, CBDCAxiosError, ExtensionAlimtalkSettingDetailParams>) => {
const mutation = useMutation<ExtensionAlimtalkSettingDetailResponse, CBDCAxiosError, ExtensionAlimtalkSettingDetailParams>({
...options,
mutationFn: (params: ExtensionAlimtalkSettingDetailParams) => extensionAlimtalkSettingDetail(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionAlimtalkSettingSaveParams,
ExtensionAlimtalkSettingSaveResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionAlimtalkSettingSave = (params: ExtensionAlimtalkSettingSaveParams) => {
return resultify(
axios.post<ExtensionAlimtalkSettingSaveResponse>(API_URL.extensionAlimtalkSettingSave(), params),
);
};
export const useExtensionAlimtalkSettingSaveMutation = (options?: UseMutationOptions<ExtensionAlimtalkSettingSaveResponse, CBDCAxiosError, ExtensionAlimtalkSettingSaveParams>) => {
const mutation = useMutation<ExtensionAlimtalkSettingSaveResponse, CBDCAxiosError, ExtensionAlimtalkSettingSaveParams>({
...options,
mutationFn: (params: ExtensionAlimtalkSettingSaveParams) => extensionAlimtalkSettingSave(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionArsApplyParams,
ExtensionArsApplyResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionArsApply = (params: ExtensionArsApplyParams) => {
return resultify(
axios.post<ExtensionArsApplyResponse>(API_URL.extensionArsApply(), params),
);
};
export const useExtensionArsApplyMutation = (options?: UseMutationOptions<ExtensionArsApplyResponse, CBDCAxiosError, ExtensionArsApplyParams>) => {
const mutation = useMutation<ExtensionArsApplyResponse, CBDCAxiosError, ExtensionArsApplyParams>({
...options,
mutationFn: (params: ExtensionArsApplyParams) => extensionArsApply(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionArsDetailParams,
ExtensionArsDetailResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionArsDetail = (params: ExtensionArsDetailParams) => {
return resultify(
axios.post<ExtensionArsDetailResponse>(API_URL.extensionArsDetail(), params),
);
};
export const useExtensionArsDetailMutation = (options?: UseMutationOptions<ExtensionArsDetailResponse, CBDCAxiosError, ExtensionArsDetailParams>) => {
const mutation = useMutation<ExtensionArsDetailResponse, CBDCAxiosError, ExtensionArsDetailParams>({
...options,
mutationFn: (params: ExtensionArsDetailParams) => extensionArsDetail(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionArsDownloadExcelParams,
ExtensionArsDownloadExcelResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionArsDownloadExcel = (params: ExtensionArsDownloadExcelParams) => {
return resultify(
axios.post<ExtensionArsDownloadExcelResponse>(API_URL.extensionArsDownloadExcel(), params),
);
};
export const useExtensionArsDownloadExcelMutation = (options?: UseMutationOptions<ExtensionArsDownloadExcelResponse, CBDCAxiosError, ExtensionArsDownloadExcelParams>) => {
const mutation = useMutation<ExtensionArsDownloadExcelResponse, CBDCAxiosError, ExtensionArsDownloadExcelParams>({
...options,
mutationFn: (params: ExtensionArsDownloadExcelParams) => extensionArsDownloadExcel(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionArsListParams,
ExtensionArsListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionArsList = (params: ExtensionArsListParams) => {
return resultify(
axios.post<ExtensionArsListResponse>(API_URL.extensionArsList(), params),
);
};
export const useExtensionArsListMutation = (options?: UseMutationOptions<ExtensionArsListResponse, CBDCAxiosError, ExtensionArsListParams>) => {
const mutation = useMutation<ExtensionArsListResponse, CBDCAxiosError, ExtensionArsListParams>({
...options,
mutationFn: (params: ExtensionArsListParams) => extensionArsList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionArsResendParams,
ExtensionArsResendResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionArsResend = (params: ExtensionArsResendParams) => {
return resultify(
axios.post<ExtensionArsResendResponse>(API_URL.extensionArsResend(), params),
);
};
export const useExtensionArsResendMutation = (options?: UseMutationOptions<ExtensionArsResendResponse, CBDCAxiosError, ExtensionArsResendParams>) => {
const mutation = useMutation<ExtensionArsResendResponse, CBDCAxiosError, ExtensionArsResendParams>({
...options,
mutationFn: (params: ExtensionArsResendParams) => extensionArsResend(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionKeyinApplyParams,
ExtensionKeyinApplyResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionKeyinApply = (params: ExtensionKeyinApplyParams) => {
return resultify(
axios.post<ExtensionKeyinApplyResponse>(API_URL.extensionKeyinApply(), params),
);
};
export const useExtensionKeyinListMutation = (options?: UseMutationOptions<ExtensionKeyinApplyResponse, CBDCAxiosError, ExtensionKeyinApplyParams>) => {
const mutation = useMutation<ExtensionKeyinApplyResponse, CBDCAxiosError, ExtensionKeyinApplyParams>({
...options,
mutationFn: (params: ExtensionKeyinApplyParams) => extensionKeyinApply(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionKeyinDownloadExcelParams,
ExtensionKeyinDownloadExcelResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionKeyinDownloadExcel = (params: ExtensionKeyinDownloadExcelParams) => {
return resultify(
axios.post<ExtensionKeyinDownloadExcelResponse>(API_URL.extensionKeyinDownloadExcel(), params),
);
};
export const useExtensionKeyinDownloadExcelMutation = (options?: UseMutationOptions<ExtensionKeyinDownloadExcelResponse, CBDCAxiosError, ExtensionKeyinDownloadExcelParams>) => {
const mutation = useMutation<ExtensionKeyinDownloadExcelResponse, CBDCAxiosError, ExtensionKeyinDownloadExcelParams>({
...options,
mutationFn: (params: ExtensionKeyinDownloadExcelParams) => extensionKeyinDownloadExcel(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionKeyinListParams,
ExtensionKeyinListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionKeyinList = (params: ExtensionKeyinListParams) => {
return resultify(
axios.post<ExtensionKeyinListResponse>(API_URL.extensionKeyinList(), params),
);
};
export const useExtensionKeyinListMutation = (options?: UseMutationOptions<ExtensionKeyinListResponse, CBDCAxiosError, ExtensionKeyinListParams>) => {
const mutation = useMutation<ExtensionKeyinListResponse, CBDCAxiosError, ExtensionKeyinListParams>({
...options,
mutationFn: (params: ExtensionKeyinListParams) => extensionKeyinList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionListParams,
ExtensionListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionList = (params: ExtensionListParams) => {
return resultify(
axios.post<ExtensionListResponse>(API_URL.extensionList(), params),
);
};
export const useExtensionListMutation = (options?: UseMutationOptions<ExtensionListResponse, CBDCAxiosError, ExtensionListParams>) => {
const mutation = useMutation<ExtensionListResponse, CBDCAxiosError, ExtensionListParams>({
...options,
mutationFn: (params: ExtensionListParams) => extensionList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionSmsDetailParams,
ExtensionSmsDetailResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionSmsDetail = (params: ExtensionSmsDetailParams) => {
return resultify(
axios.post<ExtensionSmsDetailResponse>(API_URL.extensionSmsDetail(), params),
);
};
export const useExtensionSmsListMutation = (options?: UseMutationOptions<ExtensionSmsDetailResponse, CBDCAxiosError, ExtensionSmsDetailParams>) => {
const mutation = useMutation<ExtensionSmsDetailResponse, CBDCAxiosError, ExtensionSmsDetailParams>({
...options,
mutationFn: (params: ExtensionSmsDetailParams) => extensionSmsDetail(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionSmsDownloadExcelParams,
ExtensionSmsDownloadExcelResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionSmsDownloadExcel = (params: ExtensionSmsDownloadExcelParams) => {
return resultify(
axios.post<ExtensionSmsDownloadExcelResponse>(API_URL.extensionSmsDownloadExcel(), params),
);
};
export const useExtensionSmsDownloadExcelMutation = (options?: UseMutationOptions<ExtensionSmsDownloadExcelResponse, CBDCAxiosError, ExtensionSmsDownloadExcelParams>) => {
const mutation = useMutation<ExtensionSmsDownloadExcelResponse, CBDCAxiosError, ExtensionSmsDownloadExcelParams>({
...options,
mutationFn: (params: ExtensionSmsDownloadExcelParams) => extensionSmsDownloadExcel(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionSmsListParams,
ExtensionSmsListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionSmsList = (params: ExtensionSmsListParams) => {
return resultify(
axios.post<ExtensionSmsListResponse>(API_URL.extensionSmsList(), params),
);
};
export const useExtensionSmsListMutation = (options?: UseMutationOptions<ExtensionSmsListResponse, CBDCAxiosError, ExtensionSmsListParams>) => {
const mutation = useMutation<ExtensionSmsListResponse, CBDCAxiosError, ExtensionSmsListParams>({
...options,
mutationFn: (params: ExtensionSmsListParams) => extensionSmsList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
ExtensionSmsResendParams,
ExtensionSmsResendResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const extensionSmsResend = (params: ExtensionSmsResendParams) => {
return resultify(
axios.post<ExtensionSmsResendResponse>(API_URL.extensionSmsResend(), params),
);
};
export const useExtensionSmsResendMutation = (options?: UseMutationOptions<ExtensionSmsResendResponse, CBDCAxiosError, ExtensionSmsResendParams>) => {
const mutation = useMutation<ExtensionSmsResendResponse, CBDCAxiosError, ExtensionSmsResendParams>({
...options,
mutationFn: (params: ExtensionSmsResendParams) => extensionSmsResend(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,279 @@
import { DefaulResponsePagination } from '@/entities/common/model/types';
export interface ExtensionRequestParams {
mid: string;
};
export interface ExtensionSmsResendParams extends ExtensionRequestParams {
tid: string;
};
export interface ExtensionSmsResendResponse {
};
export interface ExtensionSmsListParams extends ExtensionRequestParams {
tid: string;
searchCl: string;
searchValue: string;
fromDate: string;
toDate: string;
smsCl: string;
};
export interface ExtensionSmsListItemProps {
mid: string;
tid: string;
paymentDate: string;
paymentStatus: string;
smsCl: string;
};
export interface ExtensionSmsListResponse extends DefaulResponsePagination {
content: Array<ExtensionSmsListItemProps>
};
export interface ExtensionSmsDownloadExcelParams extends ExtensionRequestParams {
searchCl: string;
searchValue: string;
fromDate: string;
toDate: string;
smsCl: string;
};
export interface ExtensionSmsDownloadExcelResponse {
};
export interface ExtensionSmsDetailParams extends ExtensionRequestParams {
tid: string;
};
export interface ExtensionSmsDetailResponse {
senderNumber: string;
senderName: string;
receiverNumber: string;
receiverName: string;
sendMessage: string;
};
export interface ExtensionListParams extends ExtensionRequestParams {
};
export interface activeExtensionListItem {
extensionCode: string;
extensionName: string;
extensionInformation: string;
};
export interface availableExtensionListItem {
extensionCode: string;
extensionName: string;
extensionInformation: string;
};
export interface ExtensionListItemProps {
activeExtensionList: Array<activeExtensionListItem>;
availableExtensionList: Array<availableExtensionListItem>;
};
export interface ExtensionListResponse extends DefaulResponsePagination {
content: Array<ExtensionListItemProps>
};
export interface ExtensionKeyinListParams extends ExtensionRequestParams {
fromDate: string;
toDate: string;
paymentStatus: string;
minAmount: number;
maxAmount: number;
};
export interface ExtensionKeyinListItemProps {
tid: string;
paymentDate: string;
paymentStatus: string;
amount: number;
};
export interface ExtensionKeyinListResponse extends DefaulResponsePagination {
content: Array<ExtensionKeyinListItemProps>
};
export interface ExtensionKeyinDownloadExcelParams extends ExtensionRequestParams {
fromDate: string;
toDate: string;
paymentStatus: string;
minAmount: number;
maxAmount: number;
};
export interface ExtensionKeyinDownloadExcelResponse {
};
export interface ExtensionKeyinApplyParams extends ExtensionRequestParams {
goodsName: string;
amount: number;
buyerName: string;
email: string;
phoneNumber: string;
cardNo: string;
cardExpirationDate: string;
instmntMonth: string;
moid: string;
};
export interface ExtensionKeyinApplyResponse {
};
export interface ExtensionArsResendParams extends ExtensionRequestParams {
tid: string;
};
export interface ExtensionArsResendResponse {
};
export interface ExtensionArsListParams extends ExtensionRequestParams {
moid: string;
fromDate: string;
toDate: string;
paymentStatus: string;
orderStatus: string;
minAmount: number;
maxAmount: number;
};
export interface ExtensionArsListItemProps {
tid: string;
paymentDate: string;
paymentStatus: string;
orderStatus: string;
arsPaymentMethod: string;
amount: number;
};
export interface ExtensionArsListResponse extends DefaulResponsePagination {
content: Array<ExtensionArsListItemProps>
};
export interface ExtensionArsDownloadExcelParams extends ExtensionRequestParams {
moid: string;
fromDate: string;
toDate: string;
paymentStatus: string;
orderStatus: string;
minAmount: number;
maxAmount: number;
};
export interface ExtensionArsDownloadExcelResponse {
};
export interface ExtensionArsDetailParams extends ExtensionRequestParams {
tid: string;
};
export interface ExtensionArsDetailResponse {
corpName: string;
mid: string;
arsPaymentMethod: string;
paymentStatus: string;
orderStatus: string;
paymentDate: string;
goodsName: string;
tid: string;
buyerName: string;
phoneNumber: string;
maskPhoneNumber: string;
email: string;
smsVerificationCode: string;
};
export interface ExtensionArsApplyParams extends ExtensionRequestParams {
moid: string;
goodsName: string;
amount: number;
instmntMonth: string;
buyerName: string;
phoneNumber: string;
email: string;
arsPaymentMethod: string;
};
export interface ExtensionArsApplyResponse {
};
export interface SendMerchantInfoItem {
cardApprovalFlag: boolean;
cardCancelFlag: boolean;
bankApprovalFlag: boolean;
bankCancelFlag: boolean;
virtureAccountDepositRequestFlag: boolean;
virtureAccountDepositCompleteFlag: boolean;
virtureAccountRefundFlag: boolean;
};
export interface SendUserInfoItem {
cardApprovalFlag: boolean;
cardCancelFlag: boolean;
bankApprovalFlag: boolean;
bankCancelFlag: boolean;
virtureAccountDepositRequestFlag: boolean;
virtureAccountDepositCompleteFlag: boolean;
virtureAccountRefundFlag: boolean;
};
export interface ExtensionAlimtalkSettingSaveParams extends ExtensionRequestParams {
sendMerchantInfo: SendMerchantInfoItem;
sendUserInfo: SendUserInfoItem;
};
export interface ExtensionAlimtalkSettingSaveResponse {
};
export interface ExtensionAlimtalkSettingDetailParams extends ExtensionRequestParams {
};
export interface ExtensionAlimtalkSettingDetailItem {
sendMerchantInfo: SendMerchantInfoItem;
sendUserInfo: SendUserInfoItem;
};
export interface ExtensionAlimtalkSettingDetailResponse extends DefaulResponsePagination {
content: Array<ExtensionAlimtalkSettingDetailItem>
};
export interface ExtensionAlimtalkListParams extends ExtensionRequestParams {
searchCl: string;
searchValue: string;
paymentMethod: string;
alimCl: string;
fromDate: string;
toDate: string;
sendType: string;
sendCl: string;
};
export interface ExtensionAlimtalkListItem {
tid: string;
sendDate: string;
alimCl: string;
sendType: string;
sendCl: string;
paymentMethod: string;
receiverName: string;
};
export interface ExtensionAlimtalkListResponse extends DefaulResponsePagination {
content: Array<ExtensionAlimtalkListItem>
};
export interface ExtensionAlimtalkDownloadExcelParams extends ExtensionRequestParams {
searchCl: string;
searchValue: string;
paymentMethod: string;
alimCl: string;
fromDate: string;
toDate: string;
sendType: string;
sendCl: string;
};
export interface ExtensionAlimtalkDownloadExcelResponse {
};
export interface ExtensionAlimtalkDetailParams extends ExtensionRequestParams {
tid: string;
};
export interface ExtensionAlimtalkDetailResponse {
receiverName: string;
merchantName: string;
sendDate: string;
mid: string;
tid: string;
serviceName: string;
sendType: string;
senderName: string;
paymentMethod: string;
alimCl: string;
sendCl: string;
};
export interface IntroListItemProps {
className?: string;
serviceName?: string;
serviceDesc?: string;
icon?: string;
path?: string;
};
export interface ArsCardPaymentFinishProps {
requestSuccess: boolean;
setRequestSuccess: (requestSuccess: boolean) => void;
};
export interface SmsPaymentDetailResendProps {
bottomSmsPaymentDetailResendOn: boolean;
setBottomSmsPaymentDetailResendOn: (bottomSmsPaymentDetailResendOn: boolean) => void;
};

View File

@@ -0,0 +1,35 @@
import { IntroListItemProps } from '../model/types';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
export const IntroListItem = ({
className,
serviceName,
serviceDesc,
icon,
path
}: IntroListItemProps) => {
const { navigate } = useNavigate();
const onClickToNavigate = () => {
if(!!path){
navigate(path);
}
};
return (
<>
<div
className={ className }
onClick={ () => onClickToNavigate() }
>
<div>
<div className="service-name">{ serviceName }</div>
<p className="service-desc">{ serviceDesc }</p>
</div>
<img
src={ icon }
alt={ serviceName }
/>
</div>
</>
)
};

View File

@@ -0,0 +1,59 @@
import { motion } from 'framer-motion';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { SmsPaymentDetailResendProps } from '../model/types';
export const SmsPaymentDetailResend = ({
bottomSmsPaymentDetailResendOn,
setBottomSmsPaymentDetailResendOn
}: SmsPaymentDetailResendProps) => {
const variants = {
hidden: { y: '100%' },
visible: { y: '0%' },
};
const onClickToClose = () => {
// close
setBottomSmsPaymentDetailResendOn(false);
};
return (
<>
{ bottomSmsPaymentDetailResendOn &&
<div className="bg-dim"></div>
}
<motion.div
className="bottomsheet"
initial="hidden"
animate={ (bottomSmsPaymentDetailResendOn)? 'visible': 'hidden' }
variants={ variants }
transition={{ duration: 0.5 }}
>
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2>SMS & </h2>
<button
className="close-btn"
type="button"
>
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
onClick={ () => onClickToClose() }
/>
</button>
</div>
</div>
<div className="resend-info">
<div className="resend-row">() : (16610808)</div>
<div className="resend-row">() : *(010****7000)</div>
</div>
<div className="resend-box">
<p className="resend-text">[]*, 110322141414 (300 06/08 )</p>
</div>
<div className="bottomsheet-footer">
<button className="btn-50 btn-blue flex-1" type="button"></button>
</div>
</motion.div>
</>
);
};

View File

@@ -0,0 +1,5 @@
export interface AlarmItemProps {
title?: string,
category?: string,
date?: string
};

View File

@@ -0,0 +1,37 @@
import { PATHS } from '@/shared/constants/paths';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { AlarmItemProps } from '../model/types';
export const AlarmItem = ({
title,
category,
date
}: AlarmItemProps) => {
const { navigate } = useNavigate();
const onClickToNavigate = (alarmId: number) => {
let path = PATHS.support.notice.detail + alarmId;
navigate(path);
};
return (
<div className="notice-item">
<div className="notice-content">
<div className="notice-title">{ title }</div>
<div className="notice-meta">
<strong>{ category }</strong>
<span>{ date }</span>
</div>
</div>
<div
className="notice-arrow"
onClick={ () => onClickToNavigate(4) }
>
<img
src={ IMAGE_ROOT + '/Forward.svg' }
alt={ category + '바로가기' }
/>
</div>
</div>
);
};

View File

@@ -0,0 +1,40 @@
import { IMAGE_ROOT } from '@/shared/constants/common';
import { AlarmItem } from './alarm-item';
import { AlarmItemProps } from '../model/types';
export const AlarmList = () => {
const alarmItems: Array<AlarmItemProps> = [
{title: '시스템 안정화를 위한 정기 점검이 예정되어 있습니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '가맹점 관리 메뉴에 거래내역 엑셀 다운로드 기능이 추가 되었습니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '신규 가맹점을 대상으로 거래수수료 인하 혜택을 12월까지 제공합니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '앱의 안정성과 사용성을 개선한 버전 2.3.1이 출시되었습니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '점검 시간 동안 일부 서비스 이용이 제한될 수 있으니 미리 확인해주세요.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '가맹점 관리 메뉴에 거래내역 엑셀 다운로드 기능이 추가 되었습니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '신규 가맹점을 대상으로 거래수수료 인하 혜택을 12월까지 제공합니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '앱의 안정성과 사용성을 개선한 버전 2.3.1이 출시되었습니다.', category: '공지사항', date: '2025.06.01 10:00:00'},
{title: '점검 시간 동안 일부 서비스 이용이 제한될 수 있으니 미리 확인해주세요.', category: '공지사항', date: '2025.06.01 10:00:00'},
];
const getAlarmItems = () => {
let rs = [];
for(let i=0;i<alarmItems.length;i++){
rs.push(
<AlarmItem
title={ alarmItems[i]?.title }
category={ alarmItems[i]?.category }
date={ alarmItems[i]?.date }
></AlarmItem>
)
}
return rs;
};
return (
<>
<div className="notice-box sub">
{ getAlarmItems() }
</div>
<div className="notice-alert"> 알림은 90일간 보관 삭제됩니다.</div>
</>
);
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
BusinessMemberInfoParams,
BusinessMemberInfoResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const businessMemberInfo = (params: BusinessMemberInfoParams) => {
return resultify(
axios.post<BusinessMemberInfoResponse>(API_URL.businessMemberInfo(), params),
);
};
export const useBusinessMemberInfoMutation = (options?: UseMutationOptions<BusinessMemberInfoResponse, CBDCAxiosError, BusinessMemberInfoParams>) => {
const mutation = useMutation<BusinessMemberInfoResponse, CBDCAxiosError, BusinessMemberInfoParams>({
...options,
mutationFn: (params: BusinessMemberInfoParams) => businessMemberInfo(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,56 @@
export enum BusinessMemberTabKeys {
Info = 'Info',
RegistrationStatus = 'RegistrationStatus',
};
export enum BusinessMemberInfoKeys {
InfoContractManager = 'InfoContractManager',
InfoTechnicalManager = 'InfoTechnicalManager',
InfoSettlementManager = 'InfoSettlementManager',
InfoSettlementAccount = 'InfoSettlementAccount'
};
export interface BusinessMemberTabProps {
activeTab: BusinessMemberTabKeys;
};
export interface InfoArrowProps {
show?: boolean;
};
export interface BusinessMemberRequestParams {
tid?: string;
};
export interface InfoBasicInfoProps {
};
export interface InfoOwnerInfoProps {
};
export interface InfoCompanyInfoProps {
};
export interface InfoContractManagerProps {
};
export interface InfoTechnicalManagerProps {
};
export interface InfoSettlementManagerProps {
};
export interface InfoSettlementAccountProps {
};
export interface BusinessMemberInfoResponse {
InfoBasicInfo?: InfoBasicInfoProps;
InfoOwnerInfo?: InfoOwnerInfoProps;
InfoCompanyInfo?: InfoCompanyInfoProps;
infoContractManager?: InfoContractManagerProps;
infoTechnicalManager?: InfoTechnicalManagerProps;
infoSettlementManager?: InfoSettlementManagerProps;
infoSettlementAccount?: InfoSettlementAccountProps;
};
export interface InfoProps extends BusinessMemberInfoResponse{
show?: boolean;
onClickToShowInfo?: (info: BusinessMemberInfoKeys) => void;
};
export interface BusinessMemberInfoParams extends BusinessMemberRequestParams {
svcCd: string;
};

View File

@@ -0,0 +1,37 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
BusinessMemberTabKeys,
BusinessMemberTabProps
} from '../model/types';
export const BusinessMemberTab = ({
activeTab
}: BusinessMemberTabProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = (tab: BusinessMemberTabKeys) => {
if(activeTab !== tab){
if(tab === BusinessMemberTabKeys.Info){
navigate(PATHS.businessMember.info);
}
else if(tab === BusinessMemberTabKeys.RegistrationStatus){
navigate(PATHS.businessMember.registrationStatus);
}
}
};
return(
<>
<div className="subTab">
<button
className={`subtab-btn ${(activeTab === BusinessMemberTabKeys.Info)? 'active': ''}` }
onClick={ () => onClickToNavigation(BusinessMemberTabKeys.Info) }
> </button>
<button
className={`subtab-btn ${(activeTab === BusinessMemberTabKeys.RegistrationStatus)? 'active': ''}` }
onClick={ () => onClickToNavigation(BusinessMemberTabKeys.RegistrationStatus) }
></button>
</div>
</>
);
};

View File

@@ -0,0 +1,23 @@
import { useEffect, useState } from 'react';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { InfoArrowProps } from '../model/types';
export const InfoArrow = ({ show }: InfoArrowProps) => {
const [altMsg, setAltMsg] = useState<'접기' | '펼치기'>('접기');
const [className, setClassName] = useState<string>('ic20 rot-180');
useEffect(() => {
setAltMsg((show)? '접기': '펼치기');
setClassName(`ic20 ${(show)? 'rot-180': ''}`);
}, [show]);
return (
<>
<img
className={ className }
src={ IMAGE_ROOT + '/select_arrow.svg' }
alt={ altMsg }
/>
</>
);
};

View File

@@ -0,0 +1,36 @@
import { InfoProps } from '../model/types';
export const InfoBasicInfo = ({
InfoBasicInfo
}: InfoProps) => {
return (
<>
<div className="section">
<div className="section-title"></div>
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">123-45-16798</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
</ul>
</div>
</>
);
};

View File

@@ -0,0 +1,23 @@
import { InfoProps } from '../model/types';
export const InfoCompanyInfo = ({
InfoCompanyInfo
}: InfoProps) => {
return (
<>
<div className="section">
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="v"> 217()</span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="v">https://adm.dev-nicepay.co.kr:8011</span>
</li>
</ul>
</div>
</>
);
};

View File

@@ -0,0 +1,53 @@
import { motion } from 'framer-motion';
import { BusinessMemberInfoKeys, InfoProps } from '../model/types';
import { InfoArrow } from './info-arrow';
export const InfoContractManager = ({
infoContractManager,
show,
onClickToShowInfo
}: InfoProps) => {
const variants = {
hidden: { height: 0, padding: 0, display: 'none' },
visible: { height: 'auto', paddingTop: '12px', display: 'block' },
};
const onClickToSetShowInfo = () => {
if(!!onClickToShowInfo){
onClickToShowInfo(BusinessMemberInfoKeys.InfoContractManager);
}
};
return (
<>
<div className="section">
<div className="section-title"
onClick={ () => onClickToSetShowInfo() }
>
<InfoArrow show={ show }></InfoArrow>
</div>
<motion.ul
className="kv-list"
initial="hidden"
animate={ (show)? 'visible': 'hidden' }
variants={ variants }
transition={{ duration: 0.3 }}
>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">010-1234-****</span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">testkim@nicepay.co.kr</span>
<span className="v"></span>
</li>
</motion.ul>
</div>
</>
);
};

View File

@@ -0,0 +1,27 @@
import { InfoProps } from '../model/types';
export const InfoOwnerInfo = ({
InfoOwnerInfo
}: InfoProps) => {
return (
<>
<div className="section">
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="v">010-1234-1234</span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="v">testkim@nicepay.co.kr</span>
</li>
</ul>
</div>
</>
);
};

View File

@@ -0,0 +1,53 @@
import { motion } from 'framer-motion';
import { BusinessMemberInfoKeys, InfoProps } from '../model/types';
import { InfoArrow } from './info-arrow';
export const InfoSettlementAccount = ({
infoSettlementAccount,
show,
onClickToShowInfo
}: InfoProps) => {
const variants = {
hidden: { height: 0, padding: 0, display: 'none' },
visible: { height: 'auto', paddingTop: '12px', display: 'block' },
};
const onClickToSetShowInfo = () => {
if(!!onClickToShowInfo){
onClickToShowInfo(BusinessMemberInfoKeys.InfoSettlementAccount);
}
};
return (
<>
<div className="section">
<div className="section-title"
onClick={ () => onClickToSetShowInfo() }
>
<InfoArrow show={ show }></InfoArrow>
</div>
<motion.ul
className="kv-list"
initial="hidden"
animate={ (show)? 'visible': 'hidden' }
variants={ variants }
transition={{ duration: 0.3 }}
>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">123-45-16798</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
</motion.ul>
</div>
</>
);
};

View File

@@ -0,0 +1,53 @@
import { motion } from 'framer-motion';
import { BusinessMemberInfoKeys, InfoProps } from '../model/types';
import { InfoArrow } from './info-arrow';
export const InfoSettlementManager = ({
infoSettlementManager,
show,
onClickToShowInfo
}: InfoProps) => {
const variants = {
hidden: { height: 0, padding: 0, display: 'none' },
visible: { height: 'auto', paddingTop: '12px', display: 'block' },
};
const onClickToSetShowInfo = () => {
if(!!onClickToShowInfo){
onClickToShowInfo(BusinessMemberInfoKeys.InfoSettlementManager);
}
};
return (
<>
<div className="section">
<div className="section-title"
onClick={ () => onClickToSetShowInfo() }
>
<InfoArrow show={ show }></InfoArrow>
</div>
<motion.ul
className="kv-list"
initial="hidden"
animate={ (show)? 'visible': 'hidden' }
variants={ variants }
transition={{ duration: 0.3 }}
>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">010-1234-****</span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">testkim@nicepay.co.kr</span>
<span className="v"></span>
</li>
</motion.ul>
</div>
</>
);
};

View File

@@ -0,0 +1,53 @@
import { motion } from 'framer-motion';
import { BusinessMemberInfoKeys, InfoProps } from '../model/types';
import { InfoArrow } from './info-arrow';
export const InfoTechnicalManager = ({
infoTechnicalManager,
show,
onClickToShowInfo
}: InfoProps) => {
const variants = {
hidden: { height: 0, padding: 0, display: 'none' },
visible: { height: 'auto', paddingTop: '12px', display: 'block' },
};
const onClickToSetShowInfo = () => {
if(!!onClickToShowInfo){
onClickToShowInfo(BusinessMemberInfoKeys.InfoTechnicalManager);
}
};
return (
<>
<div className="section">
<div className="section-title"
onClick={ () => onClickToSetShowInfo() }
>
<InfoArrow show={ show }></InfoArrow>
</div>
<motion.ul
className="kv-list"
initial="hidden"
animate={ (show)? 'visible': 'hidden' }
variants={ variants }
transition={{ duration: 0.3 }}
>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">010-1234-****</span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">testkim@nicepay.co.kr</span>
<span className="v"></span>
</li>
</motion.ul>
</div>
</>
);
};

View File

@@ -0,0 +1,121 @@
import { useEffect, useState } from 'react';
import { useBusinessMemberInfoMutation } from '../api/use-business-member-info-mutation';
import { InfoBasicInfo } from './info-basic-info';
import { InfoOwnerInfo } from './info-owner-info';
import { InfoCompanyInfo } from './info-company-info';
import { InfoContractManager } from './info-contract-manager';
import { InfoTechnicalManager } from './info-technical-manager';
import { InfoSettlementManager } from './info-settlement-manager';
import { InfoSettlementAccount } from './info-settlement-account';
import {
BusinessMemberInfoParams,
BusinessMemberInfoResponse,
InfoContractManagerProps,
InfoTechnicalManagerProps,
InfoSettlementManagerProps,
InfoSettlementAccountProps,
BusinessMemberInfoKeys
} from '../model/types';
export const InfoWrap = () => {
const [infoContractManager, setInfoContractManager] = useState<InfoContractManagerProps>();
const [infoTechnicalManager, setInfoTechnicalManager] = useState<InfoTechnicalManagerProps>();
const [infoSettlementManager, setInfoSettlementManager] = useState<InfoSettlementManagerProps>();
const [infoSettlementAccount, setInfoSettlementAccount] = useState<InfoSettlementAccountProps>();
const [showInfoContractManager, setShowInfoContractManager] = useState<boolean>(false);
const [showInfoTechnicalManager, setShowInfoTechnicalManager] = useState<boolean>(false);
const [showInfoSettlementManager, setShowInfoSettlementManager] = useState<boolean>(false);
const [showInfoSettlementAccount, setShowInfoSettlemenAccount] = useState<boolean>(false);
const { mutateAsync: businessMemberInfo } = useBusinessMemberInfoMutation();
const callInfo = () => {
let businessMemberInfoParams: BusinessMemberInfoParams = {
svcCd: 'st',
};
businessMemberInfo(businessMemberInfoParams).then((rs: BusinessMemberInfoResponse) => {
setInfoContractManager(rs.infoContractManager);
setInfoTechnicalManager(rs.infoTechnicalManager);
setInfoSettlementManager(rs.infoSettlementManager);
setInfoSettlementAccount(rs.infoSettlementAccount);
});
};
const onClickToShowInfo = (info: BusinessMemberInfoKeys) => {
if(info === BusinessMemberInfoKeys.InfoContractManager){
setShowInfoContractManager(!showInfoContractManager);
}
else if(info === BusinessMemberInfoKeys.InfoTechnicalManager){
setShowInfoTechnicalManager(!showInfoTechnicalManager);
}
else if(info === BusinessMemberInfoKeys.InfoSettlementManager){
setShowInfoSettlementManager(!showInfoSettlementManager);
}
else if(info === BusinessMemberInfoKeys.InfoSettlementAccount){
setShowInfoSettlemenAccount(!showInfoSettlementAccount);
}
};
useEffect(() => {
callInfo();
}, []);
return (
<>
<div className="input-wrapper top-select mt-30">
<select>
<option value="1">nicetest00g</option>
<option value="2">nicetest00g</option>
<option value="3">nicetest00g</option>
</select>
</div>
<div className="merchant-info">
<InfoBasicInfo></InfoBasicInfo>
<div className="info-divider mb-16"></div>
<InfoOwnerInfo></InfoOwnerInfo>
<div className="info-divider mb-16"></div>
<InfoCompanyInfo></InfoCompanyInfo>
<div className="info-divider mb-16"></div>
<InfoContractManager
infoContractManager={ infoContractManager }
show={ showInfoContractManager }
onClickToShowInfo={ (info) => onClickToShowInfo(info) }
></InfoContractManager>
<div className="info-divider mb-16"></div>
<InfoTechnicalManager
infoTechnicalManager={ infoTechnicalManager }
show={ showInfoTechnicalManager }
onClickToShowInfo={ (info) => onClickToShowInfo(info) }
></InfoTechnicalManager>
<div className="info-divider mb-16"></div>
<InfoSettlementManager
infoSettlementManager={ infoSettlementManager }
show={ showInfoSettlementManager }
onClickToShowInfo={ (info) => onClickToShowInfo(info) }
></InfoSettlementManager>
<div className="info-divider mb-16"></div>
<InfoSettlementAccount
infoSettlementManager={ infoSettlementAccount }
show={ showInfoSettlementAccount }
onClickToShowInfo={ (info) => onClickToShowInfo(info) }
></InfoSettlementAccount>
<div className="notice-bottom left-align">
<p className="notice-tip"> .<br/>PC .</p>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,8 @@
export const RegistrationStatusWrap = () => {
return (
<>
</>
);
};

View File

@@ -0,0 +1,35 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
CodesCacheRefreshByCodeClParams,
CodesCacheRefreshByCodeClResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const codesCacheRefreshByCodeCl = ({
codeCl
}: CodesCacheRefreshByCodeClParams) => {
return resultify(
axios.post<CodesCacheRefreshByCodeClResponse>(API_URL.codesCacheRefreshByCodelCl(codeCl)),
);
};
export const useCodesCacheRefreshByCodeClMutation = (options?: UseMutationOptions<CodesCacheRefreshByCodeClResponse, CBDCAxiosError, CodesCacheRefreshByCodeClParams>) => {
const mutation = useMutation<CodesCacheRefreshByCodeClResponse, CBDCAxiosError, CodesCacheRefreshByCodeClParams>({
...options,
mutationFn: ({
codeCl
}: CodesCacheRefreshByCodeClParams) => codesCacheRefreshByCodeCl({
codeCl
}),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,26 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import { CodesCacheRefreshResponse } from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const codesCacheRefresh = () => {
return resultify(
axios.post<CodesCacheRefreshResponse>(API_URL.counselList()),
);
};
export const useCodesCacheRefreshMutation = (options?: UseMutationOptions<CodesCacheRefreshResponse, CBDCAxiosError>) => {
const mutation = useMutation<CodesCacheRefreshResponse, CBDCAxiosError>({
...options,
mutationFn: () => codesCacheRefresh(),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,26 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import { CodesCacheStatusResponse } from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const codesCacheStatus = () => {
return resultify(
axios.get<CodesCacheStatusResponse>(API_URL.codesCacheStatus()),
);
};
export const useCodesGroupByCodeClMutation = (options?: UseMutationOptions<CodesCacheStatusResponse, CBDCAxiosError>) => {
const mutation = useMutation<CodesCacheStatusResponse, CBDCAxiosError>({
...options,
mutationFn: () => codesCacheStatus(),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,33 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
CodesGroupByCodeClParams,
CodesGroupByCodeClResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const codesGroupByCodeCl = ({ codeCl }: CodesGroupByCodeClParams) => {
return resultify(
axios.get<CodesGroupByCodeClResponse>(API_URL.codesGroupByCodeCl(codeCl)),
);
};
export const useCodesGroupByCodeClMutation = (options?: UseMutationOptions<CodesGroupByCodeClResponse, CBDCAxiosError, CodesGroupByCodeClParams>) => {
const mutation = useMutation<CodesGroupByCodeClResponse, CBDCAxiosError, CodesGroupByCodeClParams>({
...options,
mutationFn: ({
codeCl
}: CodesGroupByCodeClParams) => codesGroupByCodeCl({
codeCl
}),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,33 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
CodesListByCodeClParams,
CodesListByCodeClResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const codesListByCodeCl = ({ codeCl }: CodesListByCodeClParams) => {
return resultify(
axios.get<CodesListByCodeClResponse>(API_URL.codesListByCodeCl(codeCl)),
);
};
export const useCodesListByCodeClMutation = (options?: UseMutationOptions<CodesListByCodeClResponse, CBDCAxiosError, CodesListByCodeClParams>) => {
const mutation = useMutation<CodesListByCodeClResponse, CBDCAxiosError, CodesListByCodeClParams>({
...options,
mutationFn: ({
codeCl
}: CodesListByCodeClParams) => codesListByCodeCl({
codeCl
}),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,64 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
CodesSelectParams,
CodesSelectGetResponse,
CodesSelectPostResponse,
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const codesSelect = ({
codeCl,
colNm,
code1,
code2,
useCl,
method
}: CodesSelectParams) => {
if(method === 'get'){
return resultify(
axios.get<CodesSelectGetResponse>(API_URL.codesSelect()),
);
}
else{
return resultify(
axios.post<CodesSelectPostResponse>(API_URL.codesSelect(), {
codeCl,
colNm,
code1,
code2,
useCl
}),
);
}
};
export const useCodesSelectMutation = (options?: UseMutationOptions<CodesSelectGetResponse | CodesSelectPostResponse, CBDCAxiosError, CodesSelectParams>) => {
const mutation = useMutation<CodesSelectGetResponse | CodesSelectPostResponse, CBDCAxiosError, CodesSelectParams>({
...options,
mutationFn: ({
codeCl,
colNm,
code1,
code2,
useCl,
method
}: CodesSelectParams) => codesSelect({
codeCl,
colNm,
code1,
code2,
useCl,
method
}),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
EmptyTokenAddSendCodeParams,
EmptyTokenAddSendCodeResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const emptyTokenAddSendCode = (params: EmptyTokenAddSendCodeParams) => {
return resultify(
axios.post<EmptyTokenAddSendCodeResponse>(API_URL.emptyTokenFindSendCode(), params),
);
};
export const useEmptyTokenAddSendCodeMutation = (options?: UseMutationOptions<EmptyTokenAddSendCodeResponse, CBDCAxiosError, EmptyTokenAddSendCodeParams>) => {
const mutation = useMutation<EmptyTokenAddSendCodeResponse, CBDCAxiosError, EmptyTokenAddSendCodeParams>({
...options,
mutationFn: (params: EmptyTokenAddSendCodeParams) => emptyTokenAddSendCode(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
EmptyTokenChangeParams,
EmptyTokenChangeResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const emptyTokenChange = (params: EmptyTokenChangeParams) => {
return resultify(
axios.post<EmptyTokenChangeResponse>(API_URL.emptyTokenChange(), params),
);
};
export const useEmptyTokenChangeMutation = (options?: UseMutationOptions<EmptyTokenChangeResponse, CBDCAxiosError, EmptyTokenChangeParams>) => {
const mutation = useMutation<EmptyTokenChangeResponse, CBDCAxiosError, EmptyTokenChangeParams>({
...options,
mutationFn: (params: EmptyTokenChangeParams) => emptyTokenChange(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
EmptyTokenFindSendCodeParams,
EmptyTokenFindSendCodeResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const emptyTokenFindSendCode = (params: EmptyTokenFindSendCodeParams) => {
return resultify(
axios.post<EmptyTokenFindSendCodeResponse>(API_URL.emptyTokenFindSendCode(), params),
);
};
export const useEmptyTokenFindSendCodeMutation = (options?: UseMutationOptions<EmptyTokenFindSendCodeResponse, CBDCAxiosError, EmptyTokenFindSendCodeParams>) => {
const mutation = useMutation<EmptyTokenFindSendCodeResponse, CBDCAxiosError, EmptyTokenFindSendCodeParams>({
...options,
mutationFn: (params: EmptyTokenFindSendCodeParams) => emptyTokenFindSendCode(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
EmptyTokenVerifyCodeParams,
EmptyTokenVerifyCodeResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const emptyTokenVerifyCode = (params: EmptyTokenVerifyCodeParams) => {
return resultify(
axios.post<EmptyTokenVerifyCodeResponse>(API_URL.emptyTokenVerifyCode(), params),
);
};
export const useEmptyTokenVerifyCodeMutation = (options?: UseMutationOptions<EmptyTokenVerifyCodeResponse, CBDCAxiosError, EmptyTokenVerifyCodeParams>) => {
const mutation = useMutation<EmptyTokenVerifyCodeResponse, CBDCAxiosError, EmptyTokenVerifyCodeParams>({
...options,
mutationFn: (params: EmptyTokenVerifyCodeParams) => emptyTokenVerifyCode(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,8 @@
export const DEFAULT_PAGE_PARAM = {
cursor: 'string',
size: 0,
sortBy: 'string',
sortOrder: 'ASC',
orderBy: 'string',
limit: 0,
};

View File

@@ -0,0 +1,130 @@
export interface DefaulResponsePagination {
nextCursor: string | null;
hasNext: boolean;
};
export enum HeaderType {
NoHeader = 'NoHeader',
Home = 'Home',
Alim = 'Alim',
LeftArrow = 'LeftArrow',
RightClose = 'RightClose',
};
export interface HeaderNavigationProps {
onBack?: (() => void) | undefined;
headerTitle?: string;
headerLeft?: React.ReactNode;
headerRight?: React.ReactNode;
menuOn: boolean;
headerType: HeaderType;
setMenuOn: (menuOn: boolean) => void;
};
export interface FooterProps {
setMenuOn: (menuOn: boolean) => void;
footerCurrentPage?: string | null;
};
export enum FooterItemActiveKey {
Home = 'Home',
Transaction = 'Transaction',
Settlement = 'Settlement',
Account = 'Account',
};
export interface CodesSelectParams {
codeCl?: string;
colNm?: string;
code1?: string;
code2?: string;
useCl?: string;
method: 'get' | 'post';
};
export interface CodeListItem {
codeCl: string;
code1: string;
code2: string;
desc1: string;
desc2: string;
desc3: string;
encDesc1: string;
encDesc2: string;
encDesc3: string;
colNm: string;
orderNo: number;
};
export interface CodeGroupItem {
groupCode: string;
groupType: string;
groupName: string;
codeList: Array<CodeListItem>;
};
export interface CodesSelectGetResponse {
codeGroups: Array<CodeGroupItem>;
};
export interface CodesSelectPostResponse {
codeList: Array<CodeListItem>;
};
export interface CodesListByCodeClParams {
codeCl: string;
};
export interface CodesListByCodeClResponse {
codeList: Array<CodeListItem>;
};
export interface CodesGroupByCodeClParams {
codeCl: string;
};
export interface CodesGroupByCodeClResponse extends CodeGroupItem {
}
export interface CodesCacheStatusResponse {
additionalProp1: string;
additionalProp2: string;
additionalProp3: string;
};
export interface CodesCacheRefreshResponse {
};
export interface CodesCacheRefreshByCodeClParams {
codeCl: string;
};
export interface CodesCacheRefreshByCodeClResponse {
};
export interface EmptyTokenVerifyCodeParams {
usrid: string;
authType: string;
content: string;
authCode: string;
};
export interface EmptyTokenVerifyCodeResponse {
tfaId: string;
valid: boolean;
};
export interface EmptyTokenFindSendCodeParams {
usrid: string;
password: string;
authType: string;
content: string;
};
export interface EmptyTokenFindSendCodeResponse {
expiresIn: string;
authCode: string;
};
export interface EmptyTokenChangeParams {
usrid: string;
password: string;
tfaId: string;
newPassword: string;
newConfirmPassword: string;
};
export interface EmptyTokenChangeResponse {
};
export interface EmptyTokenAddSendCodeParams {
usrid: string;
password: string;
authType: string;
content: string;
};
export interface EmptyTokenAddSendCodeResponse {
expiresIn: string;
authCode: string;
};

View 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;
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View 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>
</>
);
};

View File

@@ -0,0 +1,10 @@
export interface MenuCategoryItem {
title: string;
path: string;
};
export interface MenuCategoryProps {
category: string;
categoryIcon?: string;
items: Array<MenuCategoryItem>;
setMenuOn: (menuOn: boolean) => void;
};

View File

@@ -0,0 +1,50 @@
import { PATHS } from '@/shared/constants/paths';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { MenuCategoryProps } from '../model/types';
export const MenuCategory = ({
category,
categoryIcon,
items,
setMenuOn
}: MenuCategoryProps) => {
const { navigate } = useNavigate();
const onClickToNavigate = (path?: string) => {
if(!!path){
setMenuOn(false);
navigate(path);
}
};
const getMenuItems = () => {
let rs = [];
for(let i=0;i<items.length;i++){
let title = items[i]?.title;
let path = items[i]?.path;
let key = 'menu-item-key-'+i;
rs.push(
<li
key={ key }
onClick={ () => onClickToNavigate(path) }
>{ title }</li>
);
}
return rs;
};
return (
<>
<div className="menu-category">
<div className="category-header">
<div className={ 'category-icon ' + categoryIcon }></div>
<span>{ category }</span>
</div>
<ul className="category-items">
{ getMenuItems() }
</ul>
</div>
</>
);
};

View File

@@ -0,0 +1,7 @@
export enum PaymentTabKeys {
Info = 'Info',
DataNotification = 'DataNotification',
};
export interface PaymentTabProps {
activeTab: PaymentTabKeys;
};

View File

@@ -0,0 +1,108 @@
import { IMAGE_ROOT } from '@/shared/constants/common';
export const CardCommissionCycleBottomSheet = () => {
return (
<>
<div className="bg-dim"></div>
<div className="bottomsheet">
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2> </h2>
<button
className="close-btn"
type="button"
>
<img
src={ IMAGE_ROOT + '/images/ico_close.svg' }
alt="닫기"
/>
</button>
</div>
</div>
<div className="bottomsheet-content">
<div className="card-fee">
<div className="desc">정산주기 : 일일(+3)</div>
<div className="notice-tabs">
<button
className="tab36 on"
type="button"
></button>
<button
className="tab36"
type="button"
></button>
<button
className="tab36"
type="button"
>/</button>
</div>
<div className="card-fee-box">
<span className="label"></span>
<div className="field wid-100">
<select>
<option>KB국민</option>
</select>
</div>
</div>
<div className="card-fee-list">
<div className="card-fee-list-header">
<span className="th-left"></span>
<span className="th-right"></span>
</div>
<div className="card-fee-row">
<span>02 </span>
<span>2.000%</span>
</div>
<div className="card-fee-row">
<span>03 </span>
<span>3.100%</span>
</div>
<div className="card-fee-row">
<span>04 </span>
<span>4.400%</span>
</div>
<div className="card-fee-row">
<span>05 </span>
<span>5.200%</span>
</div>
<div className="card-fee-row">
<span>06 </span>
<span>6.000%</span>
</div>
<div className="card-fee-row">
<span>07 </span>
<span>6.600%</span>
</div>
<div className="card-fee-row">
<span>08 </span>
<span>7.500%</span>
</div>
<div className="card-fee-row">
<span>09 </span>
<span>8.000%</span>
</div>
<div className="card-fee-row">
<span>10 </span>
<span>9.000%</span>
</div>
</div>
</div>
</div>
{/*
<div className="bottomsheet-footer">
<button
className="btn-50 btn-blue flex-1"
type="button"
disabled
>신청</button>
</div>
*/}
</div>
</>
);
};

View File

@@ -0,0 +1,65 @@
import { IMAGE_ROOT } from '@/shared/constants/common';
export const CreditCardListBottomSheet = () => {
return (
<>
<div className="bg-dim"></div>
<div className="bottomsheet">
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2></h2>
<button
className="close-btn"
type="button"
>
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
/>
</button>
</div>
</div>
<div className="bottomsheet-content">
<div className="card-list">
<div className="card-option selected">
<span className="name">KB국민</span>
<i className="check"></i>
</div>
<div className="card-option">
<span className="name"></span>
<i className="check"></i>
</div>
<div className="card-option">
<span className="name">()</span>
<i className="check"></i>
</div>
<div className="card-option">
<span className="name"></span>
<i className="check"></i>
</div>
<div className="card-option">
<span className="name"></span>
<i className="check"></i>
</div>
<div className="card-option">
<span className="name"></span>
<i className="check"></i>
</div>
<div className="card-option">
<span className="name"></span>
<i className="check"></i>
</div>
</div>
</div>
<div className="bottomsheet-footer">
<button
className="btn-50 btn-blue flex-1"
type="button"
></button>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,60 @@
export const DataNotificationWrap = () => {
return (
<>
<div className="ing-list">
<div className="input-wrapper top-select mt-16">
<select>
<option value="1">nicetest00g</option>
<option value="2">nicetest00g</option>
<option value="3">nicetest00g</option>
</select>
</div>
<div className="notify-container">
<div className="notify-header">
<h3 className="notify-title"> </h3>
</div>
<ul className="notify-list">
<li>
<div className="notify-row">
<span className="notify-name"></span>
<span className="ic20 arrow-down"></span>
</div>
</li>
<li className="notify-divider"></li>
<li>
<div className="notify-row">
<span className="notify-name"></span>
<span className="ic20 arrow-down"></span>
</div>
</li>
<li className="notify-divider"></li>
<li>
<div className="notify-row">
<span className="notify-name"></span>
<span className="ic20 arrow-down"></span>
</div>
</li>
<li className="notify-divider"></li>
<li>
<div className="notify-row">
<span className="notify-name"></span>
<span className="ic20 arrow-down"></span>
</div>
</li>
<li>
<div className="notify-row">
<span className="notify-name"> </span>
<span className="ic20 arrow-down"></span>
</div>
</li>
</ul>
</div>
<div className="notify-bar">
<span> PC에서 .</span>
<span> .</span>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,363 @@
import { IMAGE_ROOT } from "@/shared/constants/common";
export const InfoWrap = () => {
return (
<>
<div className="ing-list">
<div className="ing-title"> , </div>
<ul className="ing-card-list">
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_01.svg' }
alt="신용카드"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_02.svg' }
alt="카카오페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_03.svg' }
alt="네이버페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_04.svg' }
alt="삼성페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_05.svg' }
alt="계좌이체"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_06.svg' }
alt="휴대폰결제"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_07.svg' }
alt="문화상품권"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_08.svg' }
alt="SSG머니"
/>
</div>
<span className="ing-card-name">SSG머니</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_09.svg' }
alt="TV페이"
/>
</div>
<span className="ing-card-name">TV페이</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_10.svg' }
alt="삼성페이(카드)"
/>
</div>
<span className="ing-card-name">()</span>
</div>
<button
className ="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_11.svg' }
alt="애플페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_12.svg' }
alt="토스페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_13.svg' }
alt="PAYCO"
/>
</div>
<span className="ing-card-name">PAYCO</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_14.svg' }
alt="리브페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_14.svg' }
alt="대만결제"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_15.svg' }
alt="티머니페이"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_16.svg' }
alt="L.PAY"
/>
</div>
<span className="ing-card-name">L.PAY</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_17.svg' }
alt="PAYU"
/>
</div>
<span className="ing-card-name">PAYU</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_18.svg' }
alt="TW라인페이"
/>
</div>
<span className="ing-card-name">TW라인페이</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
</ul>
<div className="ing-title"> </div>
<ul className="ing-card-list">
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_01.svg' }
alt="신용카드"
/>
</div>
<span className="ing-card-name"></span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_20.svg' }
alt="SK PAY"
/>
</div>
<span className="ing-card-name">SK PAY</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_09.svg' }
alt="TV페이"
/>
</div>
<span className="ing-card-name">TV페이</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
<li className="ing-card">
<div className="ing-card-head">
<div className="ing-card-icon">
<img
src={ IMAGE_ROOT + '/pay_04.svg' }
alt="삼성페이(카드)"
/>
</div>
<span className="ing-card-name">()</span>
</div>
<button
className="ing-card-link"
type="button"
> &gt;</button>
</li>
</ul>
</div>
</>
);
};

View File

@@ -0,0 +1,52 @@
import { IMAGE_ROOT } from '@/shared/constants/common';
export const NoInterestInfoBottomSheet = () => {
return (
<>
<div className="bg-dim"></div>
<div className="bottomsheet">
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2> </h2>
<button
className="close-btn"
type="button"
>
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
/>
</button>
</div>
</div>
<div className="fee-cycle">
<div className="card-fee-box">
<span className="label"></span>
<div className="field wid-100">
<select>
<option>KB국민</option>
</select>
</div>
</div>
<div className="desc dot">할부개월 : 02, 03, 07</div>
<div className="desc dot">적용기간 : 2025.06.01 ~ 9999.12.31</div>
<div className="desc dot">적용금액 : 70,000</div>
<div className="divider"></div>
<div className="desc dot">할부개월 : 15, 20, 36, 60</div>
<div className="desc dot">적용기간 : 2025.06.01 ~ 9999.12.31</div>
<div className="desc dot">적용금액 : 50,000</div>
</div>
{/*
<div className="bottomsheet-footer">
<button
className="btn-50 btn-blue flex-1"
type="button"
>확인</button>
</div>
*/}
</div>
</>
)
};

View File

@@ -0,0 +1,37 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
PaymentTabKeys,
PaymentTabProps
} from '../model/types';
export const PaymentTab = ({
activeTab
}: PaymentTabProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = (tab: PaymentTabKeys) => {
if(activeTab !== tab){
if(tab === PaymentTabKeys.Info){
navigate(PATHS.payment.info);
}
else if(tab === PaymentTabKeys.DataNotification){
navigate(PATHS.payment.dataNotification);
}
}
};
return(
<>
<div className="subTab">
<button
className={`subtab-btn ${(activeTab === PaymentTabKeys.Info)? 'active': ''}` }
onClick={ () => onClickToNavigation(PaymentTabKeys.Info) }
> </button>
<button
className={`subtab-btn ${(activeTab === PaymentTabKeys.DataNotification)? 'active': ''}` }
onClick={ () => onClickToNavigation(PaymentTabKeys.DataNotification) }
> </button>
</div>
</>
);
};

View File

@@ -0,0 +1,52 @@
import { IMAGE_ROOT } from '@/shared/constants/common';
export const TransferCommissionBottomSheet = () => {
return (
<>
<div className="bg-dim"></div>
<div className="bottomsheet">
<div className="bottomsheet-header">
<div className="bottomsheet-title">
<h2> </h2>
<button
className="close-btn"
type="button"
>
<img
src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기"
/>
</button>
</div>
</div>
<div className="fee-cycle">
<div className="desc dot">정산주기 : 일일(+3)</div>
<div className="desc dot"></div>
<div className="divider"></div>
<ul className="kv-list">
<li className="kv-row pl-10">
<span className="k">()</span>
<span className="v">1</span>
</li>
<li className="kv-row pl-10">
<span className="k">(1~)</span>
<span className="v">1</span>
</li>
<li className="kv-row pl-10">
<span className="k"></span>
<span className="v">1</span>
</li>
</ul>
</div>
<div className="bottomsheet-footer">
<button
className="btn-50 btn-blue flex-1"
type="button"
></button>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,41 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @cspell/spellchecker */
import { lens } from '@dhmk/zustand-lens';
import { PathType } from '~/shared/constants/paths';
export interface UtilEvents {
redirectPath?: PathType;
notiBarMessage?: string;
snackBarMessage?: string;
}
export interface UtilEventState extends UtilEvents {
setRedirectPath: (redirectPath: PathType) => void;
setNotiBarMessage: (notiBarMessage: string) => void;
setSnackBarMessage: (snackBarMessage: string) => void;
}
export const createUtilEventSlice = lens<UtilEventState>((set, get) => ({
setRedirectPath: (redirectPath) => {
set((state: UtilEventState) => {
return {
...state,
redirectPath,
};
});
},
setNotiBarMessage: (notiBarMessage) => {
set((state: UtilEventState) => {
return {
...state,
notiBarMessage,
};
});
},
setSnackBarMessage: (snackBarMessage) => {
set((state: UtilEventState) => {
return {
...state,
snackBarMessage,
};
});
},
}));

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
SettlementListParams,
SettlementListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const settlementList = (params: SettlementListParams) => {
return resultify(
axios.post<SettlementListResponse>(API_URL.settlementList(), params),
);
};
export const useSettlementListMutation = (options?: UseMutationOptions<SettlementListResponse, CBDCAxiosError, SettlementListParams>) => {
const mutation = useMutation<SettlementListResponse, CBDCAxiosError, SettlementListParams>({
...options,
mutationFn: (params: SettlementListParams) => settlementList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,110 @@
import { DefaulResponsePagination } from '@/entities/common/model/types';
export enum AltMsgKeys {
Fold = '접기',
UnFold = '펼치기',
};
export enum SortByKeys {
New = 'New',
Amount = 'Amount',
};
export enum SettlementTabKeys {
Calendar = 'calendar',
List = 'list'
};
export enum DetailInfoKeys {
Amount = 'Amount',
Settlement = 'Settlement',
};
export interface SettlementTabProps {
activeTab: SettlementTabKeys
};
export interface SettlementRequestParams {
tid?: string;
}
export interface SettlementDetailParams extends SettlementRequestParams {
svcCd: string;
};
export interface DetailAmountInfoProps {
mid: string;
amount: number;
cardAmount: number;
pointAmount: number;
couponAmount: number;
kakaoMoney: number;
kakaoPoint: number;
kakaoInstantDiscount: number;
naverPoint: number;
tossMoney: number;
tossDiscount: number;
paycoPoint: number;
paycoCoupon: number;
escrowFee: number;
};
export interface DetailSettlementInfoProps {
approvalSettleDate: string;
approvalSettleAmount: number;
cancelSettleDate: string;
cancelSettleAmount: number;
};
export interface DetailResponse {
amountInfo?: DetailAmountInfoProps;
settlementInfo?: DetailSettlementInfoProps;
};
export interface DetailInfoProps extends DetailResponse{
show?: boolean;
tid?: string;
onClickToShowInfo?: (info: DetailInfoKeys) => void;
};
export interface DetailArrowProps {
show?: boolean;
};
export interface SortOptionsBoxProps {
sortBy: SortByKeys;
onCliCkToSort: (sortBy: SortByKeys) => void;
};
export interface ListItemProps extends ListItem{
};
export interface ListDateGroupProps {
date?: string;
items?: Array<ListItemProps>;
};
export interface ListItem {
tid?: string;
mid?: string;
stateDate?: string;
stateCode?: string;
stateName?: string;
installmentMonth?: string;
serviceCode?: string;
serviceName?: string;
serviceDetailName?: string;
goodsAmount?: number;
};
export interface SettlementRequestParams {
tid?: string;
}
export interface SettlementListParams extends SettlementRequestParams {
moid: string;
fromDate: string;
toDate: string;
stateCode: string;
serviceCode: string;
minAmount: number;
maxAmount: number;
dateCl: string;
goodsName: string;
cardCode: string;
bankCode: string;
searchCl: string;
searchValue: string;
};
export interface SettlementListResponse extends DefaulResponsePagination {
content: Array<ListItemProps>;
};

View File

@@ -0,0 +1,188 @@
import { NumericFormat } from 'react-number-format';
import { IMAGE_ROOT } from '@/shared/constants/common';
export const CalendarWrap = () => {
return (
<>
<div className="calendar-wrap">
<div className="input-wrapper top-select">
<select>
<option value="1">nicetest00g</option>
<option value="2">nicetest00g</option>
<option value="3">nicetest00g</option>
</select>
</div>
<div className="month-group">
<button
className="month-btn"
aria-label="이전 달"
>
<img
src={ IMAGE_ROOT + '/ico_date_prev.svg' }
alt="이전"
/>
</button>
<div className="month-title">2024 3</div>
<button
className="month-btn"
aria-label="다음 달"
>
<img
src={ IMAGE_ROOT + '/ico_date_next.svg' }
alt="다음"
/>
</button>
</div>
<div className="amount-group">
<div className="amount-row">
<div className="amount-label"> <span className="complete"></span> </div>
<div className="amount-value">
<NumericFormat
value={ '734723983000' }
thousandSeparator
displayType="text"
suffix={ '원' }
></NumericFormat>
</div>
</div>
<div className="amount-row">
<div className="amount-label"> <span className="scheduled"></span> </div>
<div className="amount-value">
<NumericFormat
value={ '465323000' }
thousandSeparator
displayType="text"
suffix={ '원' }
></NumericFormat>
</div>
</div>
</div>
<div className="legend-group">
<div className="legend-item">
<div className="legend-dot complete"></div>
<div className="legend-text"> </div>
</div>
<div className="legend-item">
<div className="legend-dot scheduled"></div>
<div className="legend-text"> </div>
</div>
</div>
<div className="calendar-grid">
<div className="weekdays">
<div className="weekday sun"></div>
<div className="weekday"></div>
<div className="weekday"></div>
<div className="weekday"></div>
<div className="weekday"></div>
<div className="weekday"></div>
<div className="weekday sat"></div>
</div>
<div className="days">
<div className="day other">29</div>
<div className="day other">30</div>
<div className="day complete">1</div>
<div className="day">2</div>
<div className="day">3</div>
<div className="day">4</div>
<div className="day">5</div>
<div className="day">6</div>
<div className="day complete">7</div>
<div className="day">8</div>
<div className="day">9</div>
<div className="day complete">10</div>
<div className="day">11</div>
<div className="day">12</div>
<div className="day">13</div>
<div className="day">14</div>
<div className="day">15</div>
<div className="day">16</div>
<div className="day complete">17</div>
<div className="day complete">18</div>
<div className="day">19</div>
<div className="day">20</div>
<div className="day">21</div>
<div className="day">22</div>
<div className="day complete">23</div>
<div className="day">24</div>
<div className="day">25</div>
<div className="day">26</div>
<div className="day">27</div>
<div className="day scheduled">28</div>
<div className="day scheduled">29</div>
<div className="day">30</div>
<div className="day">31</div>
<div className="day other">1</div>
<div className="day other">2</div>
</div>
</div>
<div className="settlement-list">
<div className="settlement-item">
<div className="settlement-tag scheduled"></div>
<div className="settlement-date">03.29 ()</div>
<div className="settlement-amount">
<NumericFormat
value={ '34837000' }
thousandSeparator
displayType="text"
suffix={ ' 원' }
></NumericFormat>
</div>
</div>
<div className="settlement-item">
<div className="settlement-tag scheduled"></div>
<div className="settlement-date">03.28 ()</div>
<div className="settlement-amount">
<NumericFormat
value={ '834374000' }
thousandSeparator
displayType="text"
suffix={ ' 원' }
></NumericFormat>
</div>
</div>
<div className="settlement-item">
<div className="settlement-tag complete"></div>
<div className="settlement-date">03.27 ()</div>
<div className="settlement-amount">
<NumericFormat
value={ '23345000' }
thousandSeparator
displayType="text"
suffix={ ' 원' }
></NumericFormat>
</div>
</div>
<div className="settlement-item">
<div className="settlement-tag complete"></div>
<div className="settlement-date">03.25 ()</div>
<div className="settlement-amount">
<NumericFormat
value={ '84847000' }
thousandSeparator
displayType="text"
suffix={ ' 원' }
></NumericFormat>
</div>
</div>
<div className="settlement-item">
<div className="settlement-tag complete"></div>
<div className="settlement-date">03.19 ()</div>
<div className="settlement-amount">
<NumericFormat
value={ '57235000' }
thousandSeparator
displayType="text"
suffix={ ' 원' }
></NumericFormat>
</div>
</div>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,79 @@
import { motion } from 'framer-motion';
import { NumericFormat } from 'react-number-format';
import { DetailInfoKeys, DetailInfoProps } from '@/entities/settlement/model/types';
export const DetailAmountInfo = ({
amountInfo,
show,
tid,
onClickToShowInfo
}: DetailInfoProps) => {
const onClickToSetShowInfo = () => {
if(!!onClickToShowInfo){
onClickToShowInfo(DetailInfoKeys.Amount);
}
};
return (
<>
<div className="txn-section">
<div className="section-title"> </div>
<ul className="kv-list">
<li className="kv-row">
<span className="k"> </span>
<span className="v">6,017,600 (269)</span>
<ul className="txn-amount-detail">
<li>
<span>·&nbsp;&nbsp;</span>
<span>6,017,000 (260)</span>
</li>
<li>
<span>·&nbsp;&nbsp;</span>
<span>600 (9)</span>
</li>
</ul>
</li>
<li className="kv-row">
<span className="k">PG </span>
<span className="v">205,255</span>
<ul className="txn-amount-detail">
<li>
<span>·&nbsp;&nbsp;</span>
<span>165,384</span>
</li>
<li>
<span>·&nbsp;&nbsp; </span>
<span>0</span>
</li>
<li>
<span>·&nbsp;&nbsp; </span>
<span>21,300</span>
</li>
<li>
<span>·&nbsp;&nbsp;VAT</span>
<span>18,571</span>
</li>
</ul>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">0</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">0</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">- 80,603</span>
</li>
<li className="kv-row bolder">
<span className="k"></span>
<span className="v">5,731,742</span>
</li>
</ul>
</div>
</>
);
};

View File

@@ -0,0 +1,23 @@
import { useEffect, useState } from 'react';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { AltMsgKeys, DetailArrowProps } from '../model/types';
export const DetailArrow = ({ show }: DetailArrowProps) => {
const [altMsg, setAltMsg] = useState<AltMsgKeys>(AltMsgKeys.Fold);
const [className, setClassName] = useState<string>('ic20 rot-180');
useEffect(() => {
setAltMsg((show)? AltMsgKeys.Fold: AltMsgKeys.UnFold);
setClassName(`ic20 ${(show)? 'rot-180': ''}`);
}, [show]);
return (
<>
<img
className={ className }
src={ IMAGE_ROOT + '/select_arrow.svg' }
alt={ altMsg }
/>
</>
);
};

View File

@@ -0,0 +1,74 @@
import moment from 'moment';
import { motion } from 'framer-motion';
import { DetailInfoKeys, DetailInfoProps } from '@/entities/settlement/model/types';
import { DetailArrow } from './detail-arrow';
export const DetailSettlementInfo = ({
settlementInfo,
show,
onClickToShowInfo
}: DetailInfoProps) => {
const variants = {
hidden: { height: 0, padding: 0, display: 'none' },
visible: { height: 'auto', paddingTop: '12px', display: 'block' },
};
const onClickToSetShowInfo = () => {
if(!!onClickToShowInfo){
onClickToShowInfo(DetailInfoKeys.Settlement);
}
};
return (
<>
<div className="txn-section">
<div
className="section-title with-toggle"
onClick={ () => onClickToSetShowInfo() }
>
<DetailArrow show={ show }></DetailArrow>
</div>
<motion.ul
className="kv-list"
initial="hidden"
animate={ (show)? 'visible': 'hidden' }
variants={ variants }
transition={{ duration: 0.3 }}
>
<li className="kv-row">
<span className="k">MID</span>
<span className="v">cruquis01m</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">ID</span>
<span className="v">APG000600m</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">12:00:00</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">123231231****</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">5,731,742</span>
</li>
<li className="kv-row nopadding">
<span className="k"></span>
<span className="v"></span>
</li>
</motion.ul>
</div>
</>
);
};

View File

@@ -0,0 +1,50 @@
import moment from 'moment';
import 'moment/dist/locale/ko';
import { ListDateGroupProps } from '../model/types';
import { ListItem } from './list-item';
export const ListDateGroup = ({
date,
items
}: ListDateGroupProps) => {
moment.locale('ko');
const getStateDate = () => {
let stateDate = moment(date).format('YY.MM.DD(ddd)');
return stateDate;
};
const getListItem = () => {
let rs = [];
if(!!items && items.length>0){
for(let i=0;i<items.length;i++){
let key = 'ListItem-'+i;
rs.push(
<ListItem
key={ key }
tid={ items[i]?.tid }
mid={ items[i]?.mid }
stateDate={ items[i]?.stateDate }
stateCode={ items[i]?.stateCode }
stateName={ items[i]?.stateName }
installmentMonth={ items[i]?.installmentMonth }
serviceCode={ items[i]?.serviceCode }
serviceName={ items[i]?.serviceName }
serviceDetailName={ items[i]?.serviceDetailName }
goodsAmount={ items[i]?.goodsAmount }
></ListItem>
)
}
}
return rs;
};
return (
<>
<div className="date-group">
<div className="date-header">{ getStateDate() }</div>
{ getListItem() }
</div>
</>
);
};

View File

@@ -0,0 +1,99 @@
import { NumericFormat } from 'react-number-format';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { ListItemProps } from '../model/types';
export const ListItem = ({
tid,
mid,
stateDate,
stateCode,
stateName,
installmentMonth,
serviceCode,
serviceName,
serviceDetailName,
goodsAmount
}: ListItemProps) => {
const { navigate } = useNavigate();
const getItemClass = () => {
let rs = '';
if(stateCode === '0'){
rs = '';
}
else if(stateCode === '1'){
rs = 'approved';
}
else if(stateCode === '2'){
rs = 'refund';
}
return rs;
};
const getDotClass = (str?: string) => {
let rs = '';
if(stateCode === '0'){
rs = '';
}
else if(stateCode === '1'){
rs = 'blue';
}
else if(stateCode === '2'){
rs = 'gray';
}
return rs;
};
const onClickToNavigate = () => {
navigate(PATHS.settlement.detail + tid, {
state: {
tid: tid
}
});
};
const getTime = () => {
let time = stateDate?.substring(8, 12);
let timeStr = time?.substring(0, 2) + ':' + time?.substring(2, 4);
return timeStr;
};
return (
<>
<div
className={ `transaction-item ${getItemClass()}` }
onClick={ () => onClickToNavigate() }
>
<div className="transaction-status">
<div className={ `status-dot ${getDotClass()}`}></div>
</div>
<div className="transaction-content">
<div className="transaction-title">{ `${serviceName}(${serviceDetailName})` }</div>
<div className="transaction-details">
<span>{ stateName }</span>
<span className="separator">|</span>
<span>{ getTime() }</span>
<span className="separator">|</span>
<span>{ mid }</span>
{ (!!installmentMonth && parseInt(installmentMonth) > 1) &&
<>
<span className="separator">|</span>
<span>{ installmentMonth } </span>
</>
}
</div>
</div>
<div className="transaction-amount">
{
<NumericFormat
value={ goodsAmount }
thousandSeparator
displayType="text"
suffix={ '원' }
></NumericFormat>
}
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,211 @@
import moment from 'moment';
import { useEffect, useState } from 'react';
import { NumericFormat } from 'react-number-format';
import { IMAGE_ROOT } from '@/shared/constants/common';
import { ListDateGroup } from './list-date-group';
import { ListItem, ListDateGroupProps, SortByKeys } from '@/entities/settlement/model/types';
import { useSettlementListMutation } from '@/entities/settlement/api/use-settlement-list-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constants';
import { SortOptionsBox } from '@/entities/transaction/ui/sort-options-box';
export const ListWrap = () => {
const [selectedServiceCode, setSelectedServiceCode] = useState<string>('st');
const [sortBy, setSortBy] = useState<SortByKeys>(SortByKeys.New);
const [listItems, setListItems] = useState<ListDateGroupProps>({});
const [pageParam, setPageParam] = useState(DEFAULT_PAGE_PARAM);
const [fromDate, setFromDate] = useState(moment().subtract(1, 'month').format('YYYYMMDD'));
const [toDate, setToDate] = useState(moment().format('YYYYMMDD'));
const { mutateAsync: settlementList } = useSettlementListMutation();
const callList = (option?: {
sortBy?: string,
val?: string
}) => {
let listSummaryParams = {
moid: 'string',
tid: 'string',
fromDate: fromDate,
toDate: toDate,
stateCode: '0',
serviceCode: (option?.val)? option.val: selectedServiceCode,
minAmount: 0,
maxAmount: 0,
dateCl: 'TRANS',
goodsName: 'string',
cardCode: 'st',
bankCode: 'str',
searchCl: 'CARD_NO',
searchValue: 'string',
};
pageParam.sortBy = (option?.sortBy)? option.sortBy: sortBy;
setPageParam(pageParam);
let listParams = {
...listSummaryParams,
...{page: pageParam}
};
settlementList(listParams).then((rs) => {
setListItems(assembleData(rs.content));
});
};
const assembleData = (content: Array<ListItem>) => {
let data: any = {};
if(content && content.length > 0){
for(let i=0;i<content?.length;i++){
let stateDate = content[i]?.stateDate;
let groupDate = stateDate?.substring(0, 8);
if(!!groupDate && !data.hasOwnProperty(groupDate)){
data[groupDate] = [];
}
if(!!groupDate && data.hasOwnProperty(groupDate)){
data[groupDate].push(content[i]);
}
}
}
return data;
};
const onCliCkToSort = (sort: SortByKeys) => {
setSortBy(sort);
callList({sortBy: sort});
};
useEffect(() => {
callList();
}, []);
const getListDateGroup = () => {
let rs = [];
if(Object.keys(listItems).length > 0){
for (const [key, value] of Object.entries(listItems)) {
rs.push(
<ListDateGroup
key={ key }
date={ key }
items={ value }
></ListDateGroup>
);
}
}
return rs;
};
return (
<>
<div className="summary-section">
<div className="credit-controls">
<div>
<input
className="credit-period"
type="text"
value="2025.06.01 ~ 2025.06.31"
readOnly={ true }
/>
<button className="filter-btn">
<img
src={ IMAGE_ROOT + '/ico_setting.svg' }
alt="검색옵션"
/>
</button>
</div>
<button className="download-btn">
<img
src={ IMAGE_ROOT + '/ico_download.svg' }
alt="다운로드"
/>
</button>
</div>
<div className="summary-label label"></div>
<div className="summary-amount divTop">
<span className="amount-text">
<NumericFormat
value={ '83745200' }
thousandSeparator
displayType="text"
suffix={ '원' }
></NumericFormat>
</span>
<button>
<img
src={ IMAGE_ROOT + '/ico_divTop_arrow.svg' }
alt="화살표"
/>
</button>
</div>
<div className="summary-extend">
<ul className="summary-amount-list">
<li className="summary-amount-item">
<span className="label"></span>
<span className="value">
<NumericFormat
value={ '67860120' }
thousandSeparator
displayType="text"
></NumericFormat> <span className="unit"></span>
</span>
</li>
<li className="summary-amount-item">
<span className="label">PG수수료</span>
<span className="value minus">
<NumericFormat
value={ '-2409428' }
thousandSeparator
displayType="text"
></NumericFormat> <span className="unit"></span>
</span>
</li>
<li className="summary-amount-item">
<span className="label"></span>
<span className="value">
<NumericFormat
value={ '0' }
thousandSeparator
displayType="text"
></NumericFormat> <span className="unit"></span>
</span>
</li>
<li className="summary-amount-item">
<span className="label"></span>
<span className="value link">
<NumericFormat
value={ '5000' }
thousandSeparator
displayType="text"
></NumericFormat> <span className="unit"></span>
</span>
</li>
<li className="summary-amount-item">
<span className="label"></span>
<span className="value minus">
<NumericFormat
value={ '-388393' }
thousandSeparator
displayType="text"
></NumericFormat> <span className="unit"></span>
</span>
</li>
</ul>
</div>
</div>
<div className="filter-section">
<SortOptionsBox
sortBy={ sortBy }
onCliCkToSort={ onCliCkToSort }
></SortOptionsBox>
<div>
<div className="full-menu-keywords no-padding">
<span className="keyword-tag active"> </span>
<span className="keyword-tag"></span>
</div>
</div>
</div>
<div className="transaction-list">
{
(!!listItems && Object.keys(listItems).length > 0) &&
getListDateGroup()
}
</div>
</>
);
};

View File

@@ -0,0 +1,37 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
SettlementTabKeys,
SettlementTabProps
} from '../model/types';
export const SettlementTab = ({
activeTab
}: SettlementTabProps) => {
const { navigate } = useNavigate();
const onClickToNavigation = (tab: SettlementTabKeys) => {
if(activeTab !== tab){
if(tab === SettlementTabKeys.Calendar){
navigate(PATHS.settlement.calendar);
}
else if(tab === SettlementTabKeys.List){
navigate(PATHS.settlement.list);
}
}
};
return(
<>
<div className="subTab">
<button
className={`subtab-btn ${(activeTab === SettlementTabKeys.Calendar)? 'active': ''}` }
onClick={ () => onClickToNavigation(SettlementTabKeys.Calendar) }
></button>
<button
className={`subtab-btn ${(activeTab === SettlementTabKeys.List)? 'active': ''}` }
onClick={ () => onClickToNavigation(SettlementTabKeys.List) }
></button>
</div>
</>
);
};

View File

@@ -0,0 +1,22 @@
import { SortByKeys, SortOptionsBoxProps } from '../model/types';
export const SortOptionsBox = ({
sortBy,
onCliCkToSort
}: SortOptionsBoxProps) => {
return (
<>
<div className="sort-options">
<button
className={ `sort-btn ${(sortBy === SortByKeys.New)? 'active': ''}` }
onClick={ () => onCliCkToSort(SortByKeys.New) }
></button>
<span className="sort-divider">|</span>
<button
className={ `sort-btn ${(sortBy === SortByKeys.Amount)? 'active': ''}` }
onClick={ () => onCliCkToSort(SortByKeys.Amount) }
></button>
</div>
</>
);
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
CounselListParams,
CounselListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const counselList = (params: CounselListParams) => {
return resultify(
axios.post<CounselListResponse>(API_URL.counselList(), params),
);
};
export const useCounselListMutation = (options?: UseMutationOptions<CounselListResponse, CBDCAxiosError, CounselListParams>) => {
const mutation = useMutation<CounselListResponse, CBDCAxiosError, CounselListParams>({
...options,
mutationFn: (params: CounselListParams) => counselList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
CounselSaveParams,
CounselSaveResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const counselSave = (params: CounselSaveParams) => {
return resultify(
axios.post<CounselSaveResponse>(API_URL.counselSave(), params),
);
};
export const useCounselSaveMutation = (options?: UseMutationOptions<CounselSaveResponse, CBDCAxiosError, CounselSaveParams>) => {
const mutation = useMutation<CounselSaveResponse, CBDCAxiosError, CounselSaveParams>({
...options,
mutationFn: (params: CounselSaveParams) => counselSave(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
FaqListParams,
FaqListResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const faqList = (params: FaqListParams) => {
return resultify(
axios.post<FaqListResponse>(API_URL.faqList(), params),
);
};
export const useFaqListMutation = (options?: UseMutationOptions<FaqListResponse, CBDCAxiosError, FaqListParams>) => {
const mutation = useMutation<FaqListResponse, CBDCAxiosError, FaqListParams>({
...options,
mutationFn: (params: FaqListParams) => faqList(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,48 @@
import { DefaulResponsePagination } from '@/entities/common/model/types';
export interface SupportParams {
mid?: string;
};
export interface FaqListParams {
category: string;
searchValue: string;
};
export interface FaqListItemProps {
sortNo: string;
seq: string;
category: string;
categoryName: string;
title: string;
contents: string;
};
export interface FaqListResponse extends DefaulResponsePagination {
content: Array<FaqListItemProps>;
};
export interface CounselListParams extends SupportParams {
};
export interface CounselListItemProps {
sortNo: string;
seq: string;
statusCode: string;
statusName: string;
requestDate: string;
requestName: string;
title: string;
contents: string;
answer: string;
};
export interface CounselListResponse extends DefaulResponsePagination {
content: Array<CounselListItemProps>
};
export interface CounselSaveParams extends SupportParams {
counselType: string;
requestName: string;
requestTel: string;
requestEmail: string;
title: string;
contents: string;
};
export interface CounselSaveResponse {
};

View File

@@ -0,0 +1,29 @@
import axios from 'axios';
import { API_URL } from '@/shared/api/urls';
import { resultify } from '@/shared/lib/resultify';
import { CBDCAxiosError } from '@/shared/@types/error';
import {
InvoiceDetailParams,
InvoiceDetailResponse
} from '../model/types';
import {
useMutation,
UseMutationOptions
} from '@tanstack/react-query';
export const invoiceDetail = (params: InvoiceDetailParams) => {
return resultify(
axios.post<InvoiceDetailResponse>(API_URL.allTransactionList(), params),
);
};
export const useInvoiceDetailMutation = (options?: UseMutationOptions<InvoiceDetailResponse, CBDCAxiosError, InvoiceDetailParams>) => {
const mutation = useMutation<InvoiceDetailResponse, CBDCAxiosError, InvoiceDetailParams>({
...options,
mutationFn: (params: InvoiceDetailParams) => invoiceDetail(params),
});
return {
...mutation,
};
};

View File

@@ -0,0 +1,87 @@
export enum TaxTabKeys {
InvoiceList = 'InvoiceList',
VatReference = 'VatReference',
};
export interface TaxTabProps {
activeTab: TaxTabKeys;
};
export interface InvoiceFilterProps {
filterOn: boolean;
setFilterOn: (filterOn: boolean) => void;
};
export enum SortByKeys {
New = 'New',
Amount = 'Amount',
};
export interface SortOptionsBoxProps {
sortBy: SortByKeys;
onCliCkToSort: (sortBy: SortByKeys) => void;
};
export enum AltMsgKeys {
Fold = '접기',
UnFold = '펼치기',
};
export enum DetailInfoSectionKeys {
Amount = 'Amount',
Publish = 'Publish',
Receiver = 'Receiver',
Supplier = 'Supplier',
};
export interface InvoiceArrowProps {
show?: boolean;
};
export interface InvoiceListParams {
};
export interface invoiceListResponse {
};
export interface ListItem {
tid?: string;
pname?: string;
userid?: string;
idate?: string;
kind?: string;
amount?: number;
};
export interface ListItemProps extends ListItem{
};
export interface ListDateGroupProps {
date: string;
items: Array<ListItemProps>
}
export interface InvoiceListProps {
listItems: Record<string, Array<ListItemProps>>
};
export interface InvoiceDetailParams {
svcCd?: string;
tid: string;
};
export interface InvoiceDetailResponse {
};
export interface DetailAmountInfoProps {
};
export interface DetailPublishInfoProps {
};
export interface DetailReceiverInfoProps {
};
export interface DetailSupplierInfoProps {
};
export interface DetailResponse {
amountInfo?: DetailAmountInfoProps;
publishInfo?: DetailPublishInfoProps;
receiverInfo?: DetailReceiverInfoProps;
supplierInfo?: DetailSupplierInfoProps;
};
export interface DetailInfoSectionProps extends DetailResponse {
show?: boolean;
tid?: string;
onClickToShowInfo?: (info: DetailInfoSectionKeys) => void;
};

View File

@@ -0,0 +1,47 @@
import { DetailInfoSectionProps } from '../model/types';
import { InvoiceArrow } from './invoice-arrow';
export const DetailAmountInfoSection = ({
amountInfo,
show,
onClickToShowInfo
}: DetailInfoSectionProps) => {
return (
<>
<div className="txn-num-group">
<div className="txn-amount">
<div className="value">48,125,100<span className="unit"></span></div>
<button
className="chip-btn"
type="button"
>
<span></span> <InvoiceArrow show={ show }></InvoiceArrow>
</button>
</div>
<div className="amount-expand">
<ul className="amount-list">
<li className="amount-item">
<span className="label">·&nbsp;&nbsp;</span>
<span className="value">43,750,000 </span>
</li>
<li className="amount-item">
<span className="label">·&nbsp;&nbsp;VAT</span>
<span className="value">4,375,100 </span>
</li>
</ul>
</div>
<div className="txn-mid">
<span className="value">croquis01m</span>
</div>
<div className="txn-mid">
<span className="value">2025.08.19</span>
</div>
<div className="txn-doc">
<button className="doc-btn" type="button"></button>
<button className="doc-btn" type="button"></button>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,46 @@
import { DetailInfoSectionProps } from '../model/types';
export const DetailPublishInfoSection = ({
publishInfo,
show,
onClickToShowInfo
}: DetailInfoSectionProps) => {
return (
<>
<div className="txn-section">
<div className="section-title"> </div>
<ul className="kv-list">
<li className="kv-row">
<span className="k">MID</span>
<span className="v">nictest01m</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">2025.06.01 ~ 2025.06.30</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">2025.06.30</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v">PG </span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="v"></span>
</li>
<li className="kv-row">
<span className="k">Email</span>
<span className="v">test@nicepay.co.kr</span>
</li>
</ul>
</div>
</>
);
};

Some files were not shown because too many files have changed in this diff Show More