Open kirin-ri opened 1 year ago
useEffect(() => {
const showModal = () => {
// モーダルが閉じられた後に別のポップアップを表示する処理
alert("別のポップアップを表示します");
};
const modalElement = document.getElementById(props.val.physical_name + "-dtl-modal");
if (modalElement) {
modalElement.addEventListener("hidden.bs.modal", showModal);
}
return () => {
if (modalElement) {
modalElement.removeEventListener("hidden.bs.modal", showModal);
}
};
}, [props.val.physical_name]);
import React, { useState } from 'react';
interface ModalProps {
isOpen: boolean;
onClose: () => void;
}
const Modal: React.FC<ModalProps> = ({ isOpen, onClose }) => {
if (!isOpen) {
return null;
}
return (
<div>
<div>
<h2>TEST</h2>
<button onClick={onClose}>Close</button>
</div>
</div>
);
};
const App: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const handleOpen = () => {
setIsOpen(true);
};
const handleClose = () => {
setIsOpen(false);
};
return (
<div>
<button onClick={handleOpen}>Open modal</button>
<Modal isOpen={isOpen} onClose={handleClose} />
</div>
);
};
export default App;
// App.tsx
import React, { useState } from 'react';
import Modal from './Modal'; // インポート
const App: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const handleOpen = () => {
setIsOpen(true);
};
const handleClose = () => {
setIsOpen(false);
};
return (
<div>
<button onClick={handleOpen}>Open modal</button>
<Modal isOpen={isOpen} onClose={handleClose} />
</div>
);
};
export default App;
async function handleSaveBtnClicked(e: MouseEvent<HTMLButtonElement>) {
const isValid = await trigger(undefined, {shouldFocus: true});
if (!isValid) return;
// 更新値にシングルクオーテーションがある場合SQL終了文が誤認識されるため「''」にreplace
const processingForUpdate = processing.replaceAll("'", "''");
const metricsData = {
category: categorySel == "*" ? categoryTxt : categorySel,
oldMetricsName: oldMetricsName,
metricsName: metricsName,
description: description,
processing: processingForUpdate,
};
// メトリクス編集API呼び出し
commonAjax
.axios({swalFire: true, loading: true})
.post('/api/editMetrics',
metricsData,
{headers: {'Content-Type': 'application/json'}}
).then((res: any) => {
}).finally(() => {
setTextareaHeight();
});
}
async function handleSaveBtnClicked(e: MouseEvent<HTMLButtonElement>) {
const isValid = await trigger(undefined, {shouldFocus: true});
if (!isValid) return;
// 更新値にシングルクオーテーションがある場合SQL終了文が誤認識されるため「''」にreplace
const processingForUpdate = processing.replaceAll("'", "''");
const metricsData = {
category: categorySel == "*" ? categoryTxt : categorySel,
oldMetricsName: oldMetricsName,
metricsName: metricsName,
description: description,
processing: processingForUpdate,
};
// メトリクス編集API呼び出し
commonAjax
.axios({swalFire: true, loading: true})
.post('/api/editMetrics',
metricsData,
{headers: {'Content-Type': 'application/json'}}
).then((res: any) => {
}).finally(() => {
setTextareaHeight();
if (oldMetricsName === metricsName){
history.goBack();
} else{
window.location.href = "#/scm-metrics-edit/${metricsName}"
}
});
}
import { commonAjax } from '../../../components/commonAjax';
import React, { useState, useEffect, ChangeEvent, MouseEvent, FormEvent } from 'react';
import { useHistory } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import * as Defs from './metricsDefs';
import MetricsCustomizeModal from './metricsCustomizeModal';
interface MyProps {
match: {
params: {
id: string;
};
};
}
/* textareaのheightを行数によって可変設定 */
function setTextareaHeight() {
// textareaタグを全て取得
const textareaEls = document.querySelectorAll('textarea');
textareaEls.forEach((textareaEl) => {
// valueから行数を取得
const line = textareaEl.value.split('\n').length;
// 行数分のrowsに変更
textareaEl.rows = line + 3;
});
}
function MetricsEdit(props: MyProps) {
const id = props.match.params.id;
const history = useHistory();
const [metricsDetails, setMetricsDetails] = useState<Defs.MetricsDetails>();
const [categorySel, setCategorySel] = useState<string>("");
const [categoryTxt, setCategoryTxt] = useState<string>("");
const [categoryList, setCategoryList] = useState<{val: string, name: string}[]>();
const [isCategoryTxtDisplayed, setCategoryTxtDisplayed] = useState(false);
const [metricsName, setMetricsName] = useState<string>("");
const [description, setDescription] = useState<string>("");
const [processing, setProcessing] = useState<string>("");
const [oldMetricsName,setOldMetricsName] = useState<string>("");
const load = () => {
commonAjax
.axios({})
.get<string[]>('/api/categoryNames')
.then(res => {
const list = [];
res.data.map(e => list.push({val: e, name: e}));
list.push({val: "*", name: "その他..."});
setCategoryList(list);
});
commonAjax
.axios({loading: true})
.get(`/api/metrics/${id}`)
.then((res) => {
const details: Defs.MetricsDetails = res.data;
setMetricsDetails(details);
setOldMetricsName(details.id);
setMetricsName(details.id);
setCategorySel(details.category);
setDescription(details.description);
setProcessing(details.processing);
setValue("metricsName", details.id);
setValue("categoryTxt", "");
setValue("description", details.description);
setValue("processing", details.processing);
});
}
useEffect(() => {
load();
}, [history]);
useEffect(() => {
setTextareaHeight();
}, [processing]);
function handleCategorySelChanged(e: ChangeEvent<HTMLSelectElement>) {
let val = e.target.value;
setCategorySel(val);
setCategoryTxtDisplayed(val == "*");
}
function handleCategoryTxtChanged(e: ChangeEvent<HTMLInputElement>) {
categoryTxtFld.onChange(e);
setCategoryTxt(e.target.value);
}
function handleMetricsNameChanged(e: ChangeEvent<HTMLInputElement>) {
metricsNameFld.onChange(e);
setMetricsName(e.target.value);
}
function handleDescriptionChanged(e: ChangeEvent<HTMLInputElement>) {
descriptionFld.onChange(e);
setDescription(e.target.value);
}
function handleProcessingChanged(e: ChangeEvent<HTMLTextAreaElement>) {
processingFld.onChange(e);
setProcessing(e.target.value);
}
const handleCancelBtnClicked = () => {
history.goBack();
}
async function handleSaveBtnClicked(e: MouseEvent<HTMLButtonElement>) {
const isValid = await trigger(undefined, {shouldFocus: true});
if (!isValid) return;
// 更新値にシングルクオーテーションがある場合SQL終了文が誤認識されるため「''」にreplace
const processingForUpdate = processing.replaceAll("'", "''");
const metricsData = {
category: categorySel == "*" ? categoryTxt : categorySel,
oldMetricsName: oldMetricsName,
metricsName: metricsName,
description: description,
processing: processingForUpdate,
};
// メトリクス編集API呼び出し
commonAjax
.axios({swalFire: true, loading: true})
.post('/api/editMetrics',
metricsData,
{headers: {'Content-Type': 'application/json'}}
).then((res: any) => {
}).finally(() => {
setTextareaHeight();
if (oldMetricsName === metricsName){
history.goBack();
} else{
history.push(`#/scm-metrics-edit/${metricsName}`)
}
});
}
/* Validation */
const {
register,
resetField,
formState: { isDirty, isValid, errors },
trigger,
setValue,
} = useForm({
defaultValues: {
categoryTxt: categoryTxt,
metricsName: metricsName,
description: description,
processing: processing
},
mode: 'onChange',
criteriaMode: 'all',
});
const metricsNameFld = register("metricsName", {
required: {
value: true,
message: "メトリクスのタイトルを入力してください。"
}
});
const processingFld = register("processing", {
required: {
value: true,
message: "メトリクス処理内容を入力してください。"
}
});
const descriptionFld = register("description", {
required: {
value: true,
message: "説明を入力してください。"
}
});
const categoryTxtFld = register("categoryTxt", {
required: {
value: categorySel == "*",
message: "カテゴリ「その他...」を選択した場合、下の任意設定欄への入力が必要です。"
}
});
return (
<div className="content-wrapper metrics-edit">
<section className="page-cover">
<div className="page-cover-title-frame">
<h1>{metricsDetails?.category}</h1>
<div>{metricsDetails?.id}</div>
</div>
</section>
{/* Content Header (Page header) */}
<section className="content-header">
<div className="content-header-left">
<h1>メトリクス編集画面</h1>
</div>
<div className="content-header-right">
<button type="button" className="btn btn-secondary"
data-toggle="modal" data-target="#metricsCustomizeModal" disabled={!metricsDetails?.inMapping && !metricsDetails?.params}>メトリクス改修</button>
</div>
</section>
<section className="content">
<div className="edit-Form">
<div className="form-group row">
<label htmlFor="metrics-name" className="col-form-label">タイトル</label>
<div className="col col-metrics-name">
<input type="text" id="metrics-name" className="form-control" value={metricsName}
{...metricsNameFld} onChange={handleMetricsNameChanged}/>
{errors.metricsName?.message && (
<div className="text-danger">{errors.metricsName.message}</div>
)}
</div>
<label htmlFor="category-sel" className="col-form-label">カテゴリー</label>
<div className="col col-category">
<select id="category-sel" className="form-control" value={categorySel} onChange={handleCategorySelChanged}>
{categoryList?.map(e => <option key={e.val} value={e.val}>{e.name}</option>)}
</select>
{isCategoryTxtDisplayed &&
<>
<input type="text" id="category-txt" className="form-control" value={categoryTxt}
{...categoryTxtFld} onChange={handleCategoryTxtChanged}/>
{errors.categoryTxt?.message && (
<div className="text-danger">{errors.categoryTxt.message}</div>
)}
</>
}
</div>
</div>
<div className="form-group row">
<label htmlFor="description" className="col-form-label">説明</label>
<div className="col">
<input type="text" id="description" className="form-control" value={description}
{...descriptionFld} onChange={handleDescriptionChanged}/>
{errors.description?.message && (
<div className="text-danger">{errors.description.message}</div>
)}
</div>
</div>
<div className="form-group row">
<label htmlFor="processing" className="col-form-label">算出方法</label>
<div className="col">
<textarea id="processing" rows={6} className="form-control" value={processing}
{...processingFld} onChange={handleProcessingChanged}/>
{errors.processing?.message && (
<div className="text-danger">{errors.processing.message}</div>
)}
</div>
</div>
</div>
</section>
<section className="content-footer">
<p className="save-guide">上記でお間違えなければ「保存する」をクリックしてください</p>
<div style={{display:'flex'}}>
<button className="btn btn-secondary" style={{marginRight: '20px'}} onClick={handleCancelBtnClicked}>戻る</button>
<button className="btn btn-primary" onClick={handleSaveBtnClicked}>保存する</button>
</div>
</section>
<MetricsCustomizeModal id={id}/>
</div>
);
}
export default MetricsEdit;