api 공통 모듈생성
search, api 공통 모듈 생성 공통모듈 화면 별 반영
This commit is contained in:
526
src/components/common/Custom/CaliForm.js
Normal file
526
src/components/common/Custom/CaliForm.js
Normal file
@@ -0,0 +1,526 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getOptionsArray } from '../../../utils';
|
||||
import {
|
||||
SelectInput,
|
||||
SearchBarAlert
|
||||
} from '../../../styles/Components';
|
||||
import {
|
||||
FormInput, FormInputSuffix, FormInputSuffixWrapper,
|
||||
FormLabel,
|
||||
FormRowGroup,
|
||||
FormStatusBar,
|
||||
FormStatusLabel,
|
||||
FormStatusWarning,
|
||||
} from '../../../styles/ModuleComponents';
|
||||
import { CheckBox, SingleDatePicker, SingleTimePicker } from '../../common';
|
||||
import Button from '../../common/button/Button';
|
||||
import styled from 'styled-components';
|
||||
import ImageUploadBtn from '../../ServiceManage/ImageUploadBtn';
|
||||
|
||||
const CaliForm = ({
|
||||
config, // 폼 설정 JSON
|
||||
mode, // 'create', 'update', 'view' 중 하나
|
||||
initialData, // 초기 데이터
|
||||
externalData, // 외부 데이터(옵션 등)
|
||||
onSubmit, // 제출 핸들러
|
||||
onCancel, // 취소 핸들러
|
||||
className, // 추가 CSS 클래스
|
||||
onFieldValidation, // 필드 유효성 검사 콜백
|
||||
formRef // 폼 ref
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [formData, setFormData] = useState({ ...(config?.initData || {}), ...(initialData || {}) });
|
||||
const [errors, setErrors] = useState({});
|
||||
const [isFormValid, setIsFormValid] = useState(false);
|
||||
|
||||
// 필드 변경 핸들러
|
||||
const handleFieldChange = (fieldId, value) => {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[fieldId]: value
|
||||
}));
|
||||
};
|
||||
|
||||
// 날짜 변경 핸들러
|
||||
const handleDateChange = (fieldId, date) => {
|
||||
if (!date) return;
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[fieldId]: date
|
||||
}));
|
||||
};
|
||||
|
||||
// 시간 변경 핸들러
|
||||
const handleTimeChange = (fieldId, time) => {
|
||||
if (!time) return;
|
||||
|
||||
const newDateTime = formData[fieldId] ? new Date(formData[fieldId]) : new Date();
|
||||
newDateTime.setHours(time.getHours(), time.getMinutes(), 0, 0);
|
||||
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[fieldId]: newDateTime
|
||||
}));
|
||||
};
|
||||
|
||||
// 폼 유효성 검사
|
||||
useEffect(() => {
|
||||
const validateForm = () => {
|
||||
const newErrors = {};
|
||||
let isValid = true;
|
||||
|
||||
if (!config) return false;
|
||||
|
||||
// 필수 필드 검사
|
||||
const requiredFields = config.fields
|
||||
.filter(f =>
|
||||
f.visibleOn.includes(mode) &&
|
||||
f.validations?.includes("required")
|
||||
)
|
||||
.map(f => f.id);
|
||||
|
||||
requiredFields.forEach(fieldId => {
|
||||
if (!formData[fieldId] && formData[fieldId] !== 0) {
|
||||
newErrors[fieldId] = t('REQUIRED_FIELD');
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 조건부 유효성 검사
|
||||
if (config.validations && config.validations[mode]) {
|
||||
for (const validation of config.validations[mode]) {
|
||||
const conditionResult = evaluateCondition(validation.condition, {
|
||||
...formData,
|
||||
current_time: new Date().getTime()
|
||||
});
|
||||
|
||||
if (conditionResult) {
|
||||
// 전체 폼 검증 오류
|
||||
newErrors._form = t(validation.message);
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setErrors(newErrors);
|
||||
setIsFormValid(isValid);
|
||||
|
||||
if (onFieldValidation) {
|
||||
onFieldValidation(isValid, newErrors);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
};
|
||||
|
||||
validateForm();
|
||||
}, [config, formData, mode, t, onFieldValidation]);
|
||||
|
||||
// 간단한 조건식 평가 함수
|
||||
const evaluateCondition = (conditionStr, context) => {
|
||||
try {
|
||||
const fn = new Function(...Object.keys(context), `return ${conditionStr}`);
|
||||
return fn(...Object.values(context));
|
||||
} catch (e) {
|
||||
console.error('Error evaluating condition:', e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 필드 렌더링
|
||||
const renderField = (field) => {
|
||||
const isEditable = field.editableOn.includes(mode);
|
||||
const value = formData[field.id] !== undefined ? formData[field.id] : '';
|
||||
const hasError = errors[field.id];
|
||||
|
||||
switch (field.type) {
|
||||
case 'text':
|
||||
return (
|
||||
<div className="form-field">
|
||||
<FormInput
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={e => handleFieldChange(field.id, e.target.value)}
|
||||
disabled={!isEditable}
|
||||
width={field.width}
|
||||
className={hasError ? 'error' : ''}
|
||||
/>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'number':
|
||||
return (
|
||||
<div className="form-field">
|
||||
<FormInput
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={e => handleFieldChange(field.id, Number(e.target.value))}
|
||||
disabled={!isEditable}
|
||||
width={field.width}
|
||||
min={field.min}
|
||||
max={field.max}
|
||||
step={field.step || 1}
|
||||
className={hasError ? 'error' : ''}
|
||||
/>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'select':
|
||||
let options = [];
|
||||
|
||||
if (field.optionsKey) {
|
||||
// 옵션 설정에서 가져오기
|
||||
options = getOptionsArray(field.optionsKey);
|
||||
} else if (field.dataSource && externalData) {
|
||||
// 외부 데이터 소스 사용
|
||||
const dataSource = externalData[field.dataSource] || [];
|
||||
|
||||
options = dataSource.map(item => ({
|
||||
value: item[field.valueField],
|
||||
label: field.displayFormat
|
||||
? field.displayFormat.replace('{value}', item[field.valueField])
|
||||
.replace('{display}', item[field.displayField])
|
||||
: `${item[field.displayField]}(${item[field.valueField]})`
|
||||
}));
|
||||
} else if (field.options) {
|
||||
options = field.options;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="form-field">
|
||||
<SelectInput
|
||||
value={value}
|
||||
onChange={e => handleFieldChange(field.id, e.target.value)}
|
||||
disabled={!isEditable}
|
||||
width={field.width}
|
||||
className={hasError ? 'error' : ''}
|
||||
>
|
||||
{options.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</SelectInput>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'datePicker':
|
||||
return (
|
||||
<div className="form-field">
|
||||
<SingleDatePicker
|
||||
label={field.label}
|
||||
disabled={!isEditable}
|
||||
dateLabel={field.dateLabel}
|
||||
onDateChange={date => handleDateChange(field.id, date)}
|
||||
selectedDate={value}
|
||||
minDate={field.minDate}
|
||||
maxDate={field.maxDate}
|
||||
className={hasError ? 'error' : ''}
|
||||
/>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'timePicker':
|
||||
return (
|
||||
<div className="form-field">
|
||||
<SingleTimePicker
|
||||
label={field.label}
|
||||
disabled={!isEditable}
|
||||
selectedTime={value}
|
||||
onTimeChange={time => handleTimeChange(field.id, time)}
|
||||
className={hasError ? 'error' : ''}
|
||||
/>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'status':
|
||||
let statusText = "";
|
||||
if (field.optionsKey && formData[field.statusField]) {
|
||||
const statusOptions = getOptionsArray(field.optionsKey);
|
||||
const statusItem = statusOptions.find(item => item.value === formData[field.statusField]);
|
||||
statusText = statusItem ? statusItem.name : "등록";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="form-field">
|
||||
<FormStatusBar>
|
||||
<FormStatusLabel>
|
||||
{field.label}: {statusText}
|
||||
</FormStatusLabel>
|
||||
{mode === 'update' && field.warningMessage && (
|
||||
<FormStatusWarning>
|
||||
{t(field.warningMessage)}
|
||||
</FormStatusWarning>
|
||||
)}
|
||||
</FormStatusBar>
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'dateTimeRange':
|
||||
return (
|
||||
<div className="form-field">
|
||||
<div className="date-time-range">
|
||||
<SingleDatePicker
|
||||
label={field.startDateLabel}
|
||||
disabled={!isEditable}
|
||||
dateLabel={field.startDateLabel}
|
||||
onDateChange={date => handleDateChange(field.startDateField, date)}
|
||||
selectedDate={formData[field.startDateField]}
|
||||
/>
|
||||
<SingleTimePicker
|
||||
disabled={!isEditable}
|
||||
selectedTime={formData[field.startDateField]}
|
||||
onTimeChange={time => handleTimeChange(field.startDateField, time)}
|
||||
/>
|
||||
<SingleDatePicker
|
||||
label={field.endDateLabel}
|
||||
disabled={!isEditable}
|
||||
dateLabel={field.endDateLabel}
|
||||
onDateChange={date => handleDateChange(field.endDateField, date)}
|
||||
selectedDate={formData[field.endDateField]}
|
||||
/>
|
||||
<SingleTimePicker
|
||||
disabled={!isEditable}
|
||||
selectedTime={formData[field.endDateField]}
|
||||
onTimeChange={time => handleTimeChange(field.endDateField, time)}
|
||||
/>
|
||||
</div>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'imageUpload':
|
||||
const imageLanguage = field.language;
|
||||
const imageList = formData.image_list || [];
|
||||
const imageData = imageList.find(img => img.language === imageLanguage) || { content: '' };
|
||||
|
||||
return (
|
||||
<div className="form-field">
|
||||
<LanguageWrapper>
|
||||
<LanguageLabel>{imageLanguage}</LanguageLabel>
|
||||
<ImageUploadBtn
|
||||
onImageUpload={(file, fileName) => {
|
||||
const updatedImageList = [...imageList];
|
||||
const index = updatedImageList.findIndex(img => img.language === imageLanguage);
|
||||
|
||||
if (index !== -1) {
|
||||
updatedImageList[index] = {
|
||||
...updatedImageList[index],
|
||||
content: fileName
|
||||
};
|
||||
} else {
|
||||
updatedImageList.push({
|
||||
language: imageLanguage,
|
||||
content: fileName
|
||||
});
|
||||
}
|
||||
|
||||
handleFieldChange('image_list', updatedImageList);
|
||||
}}
|
||||
onFileDelete={() => {
|
||||
const updatedImageList = [...imageList];
|
||||
const index = updatedImageList.findIndex(img => img.language === imageLanguage);
|
||||
|
||||
if (index !== -1) {
|
||||
updatedImageList[index] = {
|
||||
...updatedImageList[index],
|
||||
content: ''
|
||||
};
|
||||
|
||||
handleFieldChange('image_list', updatedImageList);
|
||||
}
|
||||
}}
|
||||
fileName={imageData.content}
|
||||
disabled={!isEditable}
|
||||
/>
|
||||
</LanguageWrapper>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'checkbox':
|
||||
return (
|
||||
<div className="form-field">
|
||||
<CheckBox
|
||||
label={field.label}
|
||||
id={field.id}
|
||||
checked={formData[field.id] || false}
|
||||
setData={e => handleFieldChange(field.id, e.target.checked)}
|
||||
disabled={!isEditable}
|
||||
/>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'textWithSuffix':
|
||||
const linkLanguage = field.suffix;
|
||||
const linkList = formData.link_list || [];
|
||||
const linkData = linkList.find(link => link.language === linkLanguage) || { content: '' };
|
||||
|
||||
return (
|
||||
<div className="form-field">
|
||||
{field.label && <FormLabel>{field.label}</FormLabel>}
|
||||
<FormInputSuffixWrapper>
|
||||
<FormInput
|
||||
type="text"
|
||||
value={linkData.content}
|
||||
onChange={e => {
|
||||
const updatedLinkList = [...linkList];
|
||||
const index = updatedLinkList.findIndex(link => link.language === linkLanguage);
|
||||
|
||||
if (index !== -1) {
|
||||
updatedLinkList[index] = {
|
||||
...updatedLinkList[index],
|
||||
content: e.target.value
|
||||
};
|
||||
} else {
|
||||
updatedLinkList.push({
|
||||
language: linkLanguage,
|
||||
content: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
handleFieldChange('link_list', updatedLinkList);
|
||||
}}
|
||||
disabled={!isEditable}
|
||||
width={field.width}
|
||||
suffix="true"
|
||||
/>
|
||||
<FormInputSuffix>{linkLanguage}</FormInputSuffix>
|
||||
</FormInputSuffixWrapper>
|
||||
{hasError && <div className="field-error">{hasError}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// 조건부 렌더링을 위한 필드 필터링
|
||||
const getVisibleFields = () => {
|
||||
if (!config) return [];
|
||||
|
||||
return config.fields.filter(field => {
|
||||
if (!field.visibleOn.includes(mode)) return false;
|
||||
|
||||
// 조건부 표시 필드 처리
|
||||
if (field.conditional) {
|
||||
const { field: condField, operator, value } = field.conditional;
|
||||
|
||||
if (operator === "==" && formData[condField] !== value) return false;
|
||||
if (operator === "!=" && formData[condField] === value) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
// 그리드 기반 필드 렌더링
|
||||
const renderGridFields = () => {
|
||||
if (!config) return null;
|
||||
|
||||
const visibleFields = getVisibleFields();
|
||||
const { rows, columns } = config.grid;
|
||||
|
||||
// 그리드 레이아웃 생성
|
||||
return (
|
||||
<div className="form-grid" style={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, 1fr)`, gap: '10px' }}>
|
||||
{visibleFields.map((field) => {
|
||||
const { row, col, width } = field.position;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={field.id}
|
||||
className="form-cell"
|
||||
style={{
|
||||
gridRow: row + 1,
|
||||
gridColumn: `${col + 1} / span ${width}`,
|
||||
padding: '5px'
|
||||
}}
|
||||
>
|
||||
<FormRowGroup>
|
||||
<FormLabel>{field.label}{field.validations?.includes("required") && <span className="required">*</span>}</FormLabel>
|
||||
{renderField(field)}
|
||||
</FormRowGroup>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 버튼 렌더링
|
||||
const renderButtons = () => {
|
||||
if (!config || !config.actions || !config.actions[mode]) return null;
|
||||
|
||||
return (
|
||||
<div className="form-actions">
|
||||
{config.actions[mode].map(action => (
|
||||
<Button
|
||||
key={action.id}
|
||||
text={action.label}
|
||||
theme={action.theme}
|
||||
handleClick={() => {
|
||||
if (action.action === 'submit') {
|
||||
if (isFormValid) {
|
||||
onSubmit(formData);
|
||||
}
|
||||
} else if (action.action === 'close' || action.action === 'cancel') {
|
||||
onCancel();
|
||||
}
|
||||
}}
|
||||
disabled={action.action === 'submit' && !isFormValid}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
if (!config) return <div>로딩 중...</div>;
|
||||
|
||||
return (
|
||||
<div className={`json-config-form ${className || ''}`} ref={formRef}>
|
||||
<div className="form-content">
|
||||
{renderGridFields()}
|
||||
|
||||
{errors._form && (
|
||||
<SearchBarAlert $marginTop="15px" $align="right">
|
||||
{errors._form}
|
||||
</SearchBarAlert>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="form-footer">
|
||||
{renderButtons()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CaliForm;
|
||||
|
||||
const LanguageWrapper = styled.div`
|
||||
width: ${props => props.width || '100%'};
|
||||
//margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 90px;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const LanguageLabel = styled.h4`
|
||||
color: #444;
|
||||
margin: 0 0 10px 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
`;
|
||||
@@ -3,14 +3,16 @@ import { StatusLabel } from '../../../styles/ModuleComponents';
|
||||
import { Button, CheckBox } from '../index';
|
||||
import { convertKTC, getOptionsArray } from '../../../utils';
|
||||
import { styled } from 'styled-components';
|
||||
import { TableSkeleton } from '../../Skeleton/TableSkeleton';
|
||||
|
||||
const CaliTable = ({
|
||||
columns,
|
||||
data,
|
||||
selectedRows = [],
|
||||
onSelectRow,
|
||||
isRowSelected,
|
||||
onAction,
|
||||
refProp
|
||||
refProp,
|
||||
loading = false
|
||||
}) => {
|
||||
|
||||
const renderCell = (column, item) => {
|
||||
@@ -51,7 +53,7 @@ const CaliTable = ({
|
||||
name={column.name || 'select'}
|
||||
id={item.id}
|
||||
setData={(e) => onSelectRow(e, item)}
|
||||
checked={selectedRows.some(row => row.id === item.id)}
|
||||
checked={isRowSelected(item.id)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -74,6 +76,7 @@ const CaliTable = ({
|
||||
};
|
||||
|
||||
return (
|
||||
loading ? <TableSkeleton count={15}/> :
|
||||
<TableWrapper>
|
||||
<TableStyle ref={refProp}>
|
||||
<caption></caption>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { styled } from 'styled-components';
|
||||
import { TextInput, SelectInput, SearchBarAlert, BtnWrapper } from '../../../styles/Components';
|
||||
import {
|
||||
BtnWrapper,
|
||||
SearchRow,
|
||||
SearchbarStyle, SearchItem,
|
||||
} from '../../../styles/Components';
|
||||
import Button from '../button/Button';
|
||||
|
||||
const SearchBarLayout = ({ firstColumnData, secondColumnData, filter, direction, onReset, handleSubmit, isSearch = true }) => {
|
||||
@@ -36,42 +39,4 @@ const SearchBarLayout = ({ firstColumnData, secondColumnData, filter, direction,
|
||||
|
||||
export default SearchBarLayout;
|
||||
|
||||
const SearchbarStyle = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ddd;
|
||||
margin: 0 0 40px;
|
||||
flex-flow: ${props => props.direction};
|
||||
gap: ${props => (props.direction === 'column' ? '20px' : '20px 0')};
|
||||
`;
|
||||
|
||||
const SearchItem = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-right: 50px;
|
||||
|
||||
${TextInput}, ${SelectInput} {
|
||||
height: 35px;
|
||||
}
|
||||
${TextInput} {
|
||||
padding: 0 10px;
|
||||
max-width: 400px;
|
||||
}
|
||||
`;
|
||||
|
||||
const SearchRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 0;
|
||||
|
||||
&:last-child {
|
||||
border-top: 1px solid #e0e0e0;
|
||||
padding-top: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -13,7 +13,10 @@ const TableHeader = ({
|
||||
handlePageSize,
|
||||
selectedRows = [],
|
||||
onAction,
|
||||
navigate
|
||||
navigate,
|
||||
pagination,
|
||||
goToNextPage,
|
||||
goToPrevPage
|
||||
}) => {
|
||||
const userInfo = useRecoilValue(authList);
|
||||
const { t } = useTranslation();
|
||||
@@ -48,7 +51,7 @@ const TableHeader = ({
|
||||
);
|
||||
}
|
||||
|
||||
const buttonTheme = button.disableWhen === 'noSelection' && selectedRows.length === 0
|
||||
const buttonTheme = (button.disableWhen === 'noSelection' && selectedRows.length === 0) || button.disableWhen === 'disable'
|
||||
? 'disable'
|
||||
: button.theme;
|
||||
|
||||
@@ -58,6 +61,7 @@ const TableHeader = ({
|
||||
theme={buttonTheme}
|
||||
text={button.text}
|
||||
handleClick={(e) => handleButtonClick(button, e)}
|
||||
disabled={button.disableWhen === 'disable'}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -71,6 +75,9 @@ const TableHeader = ({
|
||||
orderType={config.orderType}
|
||||
pageType={config.pageType}
|
||||
countType={config.countType}
|
||||
pagination={pagination}
|
||||
goToNextPage={goToNextPage}
|
||||
goToPrevPage={goToPrevPage}
|
||||
>
|
||||
{config.buttons.map(renderButton)}
|
||||
</ViewTableInfo>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
HeaderPaginationContainer,
|
||||
ListCount,
|
||||
ListOption,
|
||||
SelectInput,
|
||||
@@ -6,6 +7,8 @@ import {
|
||||
} from '../../../styles/Components';
|
||||
import { ORDER_OPTIONS, PAGE_SIZE_OPTIONS, ViewTitleCountType } from '../../../assets/data';
|
||||
import { TitleItem, TitleItemLabel, TitleItemValue } from '../../../styles/ModuleComponents';
|
||||
import { DynamoPagination } from '../index';
|
||||
import React from 'react';
|
||||
|
||||
const ViewTableInfo = ({
|
||||
children,
|
||||
@@ -15,7 +18,10 @@ const ViewTableInfo = ({
|
||||
handleOrderBy,
|
||||
pageType = 'default',
|
||||
handlePageSize,
|
||||
countType = ViewTitleCountType.total
|
||||
countType = ViewTitleCountType.total,
|
||||
pagination,
|
||||
goToNextPage,
|
||||
goToPrevPage
|
||||
}) => {
|
||||
return (
|
||||
<TableInfo>
|
||||
@@ -26,9 +32,18 @@ const ViewTableInfo = ({
|
||||
COUNT_TYPE_RENDERERS[ViewTitleCountType.total](total, total_all)}
|
||||
</ListCount>
|
||||
}
|
||||
{pagination !== undefined && goToNextPage !== undefined && goToPrevPage !== undefined &&
|
||||
<HeaderPaginationContainer>
|
||||
<DynamoPagination
|
||||
pagination={pagination}
|
||||
onNextPage={goToNextPage}
|
||||
onPrevPage={goToPrevPage}
|
||||
/>
|
||||
</HeaderPaginationContainer>
|
||||
}
|
||||
<ListOption>
|
||||
<OrderBySelect orderType={orderType} handleOrderBy={handleOrderBy} />
|
||||
<PageSelect pageType={pageType} handlePageSize={handlePageSize} />
|
||||
{handleOrderBy !== undefined && <OrderBySelect orderType={orderType} handleOrderBy={handleOrderBy} />}
|
||||
{handlePageSize !== undefined && <PageSelect pageType={pageType} handlePageSize={handlePageSize} />}
|
||||
{children}
|
||||
</ListOption>
|
||||
</TableInfo>
|
||||
|
||||
@@ -3,7 +3,7 @@ import Button from '../button/Button';
|
||||
import Modal from './Modal';
|
||||
import { modalTypes } from '../../../assets/data';
|
||||
|
||||
const DynamicModal = ({modalType, view, handleSubmit, handleCancel, modalText, children}) => {
|
||||
const DynamicModal = ({modalType, view, handleSubmit, handleCancel, modalText, children, ChildView}) => {
|
||||
if (!view) return null;
|
||||
|
||||
const OkButton = ({handleClick}) => {
|
||||
@@ -58,7 +58,7 @@ const DynamicModal = ({modalType, view, handleSubmit, handleCancel, modalText, c
|
||||
<ButtonClose onClick={handleCancel} />
|
||||
</BtnWrapper>
|
||||
<ModalText $align="center">
|
||||
{children && children}
|
||||
{ChildView && <ChildView />}
|
||||
</ModalText>
|
||||
<BtnWrapper $gap="10px">
|
||||
<Button text="취소" theme="line" size="large" width="100%" handleClick={handleCancel} />
|
||||
|
||||
Reference in New Issue
Block a user