첫 커밋

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

47
src/types/api.ts Normal file
View File

@@ -0,0 +1,47 @@
export interface ApiResponse<T = unknown> {
success: boolean;
data: T;
message: string;
timestamp: string;
}
export interface ApiErrorResponse {
success: false;
error: {
code: string;
message: string;
details?: any;
};
timestamp: string;
}
export interface PaginatedResponse<T> {
data: T[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
export interface ApiRequestConfig {
timeout?: number;
retries?: number;
retryDelay?: number;
headers?: Record<string, any>;
}
export interface FileUploadProgress {
loaded: number;
total: number;
percentage: number;
}
export interface FileUploadResponse {
fileId: string;
filename: string;
url: string;
size: number;
mimeType: string;
}

62
src/types/auth.ts Normal file
View File

@@ -0,0 +1,62 @@
export interface LoginCredentials {
email: string;
password: string;
}
export interface RegisterData {
email: string;
password: string;
name: string;
phone?: string;
}
export interface UserInfo {
id: string;
email: string;
name: string;
phone?: string;
role: UserRole;
createdAt: string;
updatedAt: string;
}
export enum UserRole {
ADMIN = 'admin',
USER = 'user',
MERCHANT = 'merchant'
}
export interface JWTPayload {
userId: string;
email: string;
role: UserRole;
iat: number;
exp: number;
}
export interface AuthState {
isAuthenticated: boolean;
user: UserInfo | null;
token: string | null;
isLoading: boolean;
}
export interface AuthContextType extends AuthState {
login: (credentials: LoginCredentials) => Promise<void>;
register: (data: RegisterData) => Promise<void>;
logout: () => void;
refreshToken: () => Promise<void>;
hasRole: (role: UserRole) => boolean;
hasPermission: (permission: string) => boolean;
}
// Type aliases for React Query hooks
export type User = UserInfo;
export interface UserPermission {
id: string;
name: string;
description?: string;
resource: string;
action: string;
}

89
src/types/bridge.ts Normal file
View File

@@ -0,0 +1,89 @@
export interface AppBridgeMessage {
type: string;
data?: any;
callback?: string;
}
export interface AppBridgeResponse {
success: boolean;
data?: any;
error?: string;
}
export enum BridgeMessageType {
// 네이티브 앱 정보
GET_APP_INFO = 'getAppInfo',
GET_DEVICE_INFO = 'getDeviceInfo',
// 네비게이션
NAVIGATE_BACK = 'navigateBack',
NAVIGATE_TO = 'navigateTo',
NAVIGATE_TO_LOGIN = 'navigateToLogin',
CLOSE_WEBVIEW = 'closeWebView',
// 알림
SHOW_TOAST = 'showToast',
SHOW_ALERT = 'showAlert',
SHOW_CONFIRM = 'showConfirm',
// 결제
PROCESS_PAYMENT = 'processPayment',
CANCEL_PAYMENT = 'cancelPayment',
// 저장소
SET_STORAGE = 'setStorage',
GET_STORAGE = 'getStorage',
REMOVE_STORAGE = 'removeStorage',
// 카메라/갤러리
OPEN_CAMERA = 'openCamera',
OPEN_GALLERY = 'openGallery',
// 위치
GET_LOCATION = 'getLocation',
// 연락처
GET_CONTACTS = 'getContacts',
// 공유
SHARE_CONTENT = 'shareContent',
// 인증
LOGIN = 'login',
LOGOUT = 'logout',
// 언어 설정
SET_LANGUAGE = 'setLanguage',
GET_LANGUAGE = 'getLanguage',
// 메시지 카운트 업데이트
UPDATE_MESSAGE_COUNT = 'updateMessageCount'
}
export interface DeviceInfo {
platform: 'ios' | 'android';
version: string;
model: string;
uuid: string;
appVersion: string;
}
export interface LocationInfo {
latitude: number;
longitude: number;
accuracy: number;
timestamp: number;
}
export interface ContactInfo {
name: string;
phone: string;
email?: string;
}
export interface ShareContent {
title: string;
text: string;
url?: string;
image?: string;
}

117
src/types/filter.ts Normal file
View File

@@ -0,0 +1,117 @@
export type DatePeriod = '1month' | '3months' | '6months' | 'custom';
export type TransactionType = 'all' | 'deposit' | 'withdrawal';
export type SortOrder = 'latest' | 'oldest';
export interface DateRange {
startDate: Date;
endDate: Date;
}
export interface SearchFilter {
period: DatePeriod;
dateRange?: DateRange;
transactionType: TransactionType;
sortOrder: SortOrder;
}
export interface SearchFilterOptions {
periods: Array<{
value: DatePeriod;
label: string;
}>;
transactionTypes: Array<{
value: TransactionType;
label: string;
}>;
sortOrders: Array<{
value: SortOrder;
label: string;
}>;
}
export interface SearchFilterModalProps {
isOpen: boolean;
onClose: () => void;
onConfirm: (filter: SearchFilter) => void;
initialFilter?: SearchFilter;
options?: Partial<SearchFilterOptions>;
}
// 기본 옵션 상수
// locale 적용: label을 i18n key로 지정
export const DEFAULT_FILTER_OPTIONS: SearchFilterOptions = {
periods: [
{ value: '1month', label: 'filter.periods.1month' },
{ value: '3months', label: 'filter.periods.3months' },
{ value: '6months', label: 'filter.periods.6months' },
{ value: 'custom', label: 'filter.periods.custom' }
],
transactionTypes: [
{ value: 'all', label: 'filter.transactionTypes.all' },
{ value: 'deposit', label: 'filter.transactionTypes.deposit' },
{ value: 'withdrawal', label: 'filter.transactionTypes.withdrawal' }
],
sortOrders: [
{ value: 'latest', label: 'filter.sortOrders.latest' },
{ value: 'oldest', label: 'filter.sortOrders.oldest' }
]
};
// 기본 필터 값
export const DEFAULT_SEARCH_FILTER: SearchFilter = {
period: '1month',
transactionType: 'all',
sortOrder: 'latest'
};
// 날짜 유틸리티 함수들
export const getDateRangeFromPeriod = (period: DatePeriod): DateRange | null => {
const endDate = new Date();
const startDate = new Date();
switch (period) {
case '1month':
startDate.setMonth(endDate.getMonth() - 1);
break;
case '3months':
startDate.setMonth(endDate.getMonth() - 3);
break;
case '6months':
startDate.setMonth(endDate.getMonth() - 6);
break;
case 'custom':
return null; // 사용자가 직접 설정
default:
return null;
}
return { startDate, endDate };
};
export const formatDateRange = (dateRange: DateRange): string => {
const formatDate = (date: Date) => {
return date.toLocaleDateString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
};
return `${formatDate(dateRange.startDate)} ~ ${formatDate(dateRange.endDate)}`;
};
export const getFilterDisplayText = (filter: SearchFilter, t: (key: string) => string): string => {
const periodOption = DEFAULT_FILTER_OPTIONS.periods.find(p => p.value === filter.period);
const transactionOption = DEFAULT_FILTER_OPTIONS.transactionTypes.find(tt => tt.value === filter.transactionType);
const sortOption = DEFAULT_FILTER_OPTIONS.sortOrders.find(s => s.value === filter.sortOrder);
const parts = [
periodOption?.label ? t(periodOption.label) : undefined,
transactionOption?.label ? t(transactionOption.label) : undefined,
sortOption?.label ? t(sortOption.label) : undefined
].filter(Boolean);
return parts.join(' · ');
};

4
src/types/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export * from './auth';
export * from './api';
export * from './bridge';
export * from './filter';