import type{ SelectComponentListenerType } from "../../hooks/useComponent";
import { ButtonActionTypeMap } from "../../types/action";
import type { ButtonActionType, ButtonAddDataAction, ButtonDeleteDataAction, ButtonNavigateAction, ButtonSearchDataAction, ButtonUpdateDataAction } from "../../types/action";
import type { ButtonComponent, Component } from "../../types/component";
import type { Screen } from "../../types/screen";
import type { Table } from "../../types/table";
import { useEffect, useState } from "react"
import { MdEdit } from "react-icons/md";
interface ButtonActionPropertiesProps {
component: ButtonComponent
screens: Screen[],
curScreenIndex: number,
tables: Table[],
updateComponent: (index: number, newComponent: Component) => void,
setSelectComponentListener: (listener: SelectComponentListenerType) => void
activateSelectMode: () => void
}
export function ButtonActionProperties({
component,
screens,
curScreenIndex,
tables,
updateComponent,
setSelectComponentListener,
activateSelectMode
}: ButtonActionPropertiesProps) {
const buttonAction = component.action?.type ?? "";
const [action, setAction] = useState<ButtonActionType | "">(component.action?.type ?? "");
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setAction(buttonAction)
}, [buttonAction])
return (
<div className="flex flex-col">
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
アクション
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={action}
onChange={(e) => setAction(e.target.value as (ButtonActionType | ""))}
>
<option value={""}>選択してください</option>
{Object.keys(ButtonActionTypeMap).map((key) =>
<option key={key} value={key}>{key}</option>
)}
</select>
</div>
{action === "navigate" && <NavigateProperties
component={component}
screens={screens}
curScreenIndex={curScreenIndex}
updateComponent={updateComponent}
/>}
{action === "addData" && <AddDataProperties
component={component}
screens={screens}
tables={tables}
updateComponent={updateComponent}
setSelectComponentListener={setSelectComponentListener}
activateSelectMode={activateSelectMode}
/>}
{action === "updateData" && <UpdateDataProperties
component={component}
screens={screens}
tables={tables}
updateComponent={updateComponent}
setSelectComponentListener={setSelectComponentListener}
activateSelectMode={activateSelectMode}
/>}
{action === "deleteData" && <DeleteDataProperties
component={component}
screens={screens}
tables={tables}
updateComponent={updateComponent}
setSelectComponentListener={setSelectComponentListener}
activateSelectMode={activateSelectMode}
/>}
{action === "searchData" && <SearchDataProperties
component={component}
tables={tables}
updateComponent={updateComponent}
setSelectComponentListener={setSelectComponentListener}
activateSelectMode={activateSelectMode}
/>}
</div>
)
}
interface NavigatePropertiesProps {
component: ButtonComponent
screens: Screen[],
curScreenIndex: number,
updateComponent: (index: number, component: Component) => void
}
function NavigateProperties({
screens,
curScreenIndex,
component,
updateComponent,
}: NavigatePropertiesProps) {
const originalScreenName = (component.action?.action as ButtonNavigateAction)?.nextScreenName ?? "";
const [screenName, setScreenName] = useState<string>(originalScreenName);
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setScreenName(originalScreenName)
}, [originalScreenName])
const validate = () => {
if (!screenName.trim()) {
return false;
}
if (screenName === "") {
return false;
}
return true;
}
const handleConfirm = () => {
const navigateAction: ButtonNavigateAction = {
nextScreenName: screenName
}
const newComponent: ButtonComponent = { ...component, action: { type: "navigate", action: navigateAction } }
updateComponent(-1, newComponent);
}
return (
<div className="flex-col">
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
遷移先スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={screenName}
onChange={(e) => setScreenName(e.target.value)}
>
<option value={""}>選択してください</option>
<option value="_back">戻る</option>
{screens.filter((_, idx) => idx !== curScreenIndex).map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
<div className="mb-4 flex justify-end">
{validate() &&
<button
onClick={handleConfirm}
disabled={(component.action?.action as ButtonNavigateAction)?.nextScreenName === screenName}
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed rounded-lg transition-colors"
>
決定
</button>
}
</div>
</div>
)
}
interface AddDataPropertiesProps {
component: ButtonComponent
screens: Screen[]
tables: Table[]
updateComponent: (index: number, newComponent: Component) => void,
setSelectComponentListener: (listener: SelectComponentListenerType) => void
activateSelectMode: () => void
}
function AddDataProperties({
component,
screens,
tables,
updateComponent,
setSelectComponentListener,
activateSelectMode
}: AddDataPropertiesProps) {
const buttonAction =
(component.action?.type ?? "") === "addData"
? component.action?.action as ButtonAddDataAction
: {
tableName: "",
newData: {},
failScreenName: "",
successScreenName: ""
};
const [tableName, setTableName] = useState<string>(buttonAction?.tableName ?? "");
const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.newData ?? {});
const [selectModeButton, setSelectModeButton] = useState<string>("");
const [successScreen, setSuccessScreen] = useState<string>(buttonAction?.successScreenName ?? "")
const [failScreen, setFailScreen] = useState<string>(buttonAction?.failScreenName ?? "")
const handleTableChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setTableName(e.target.value);
const res: { [key: string]: string } = {}
for (const col of tables.find((table) => table.name === e.target.value)?.columns ?? []) {
if (!col.foreignTableName) {
res[col.name] = "";
} else {
const ftable = tables.find((table) => table.name === col.foreignTableName);
for (const fcol of ftable?.columns ?? []) {
if (fcol.isPrimary) {
res[`${ftable?.name}.${fcol.name}`] = "";
}
}
}
}
setData(res);
setSuccessScreen("");
setFailScreen("");
}
const handleChange = (key: string, value: string) => {
setData(prev => ({ ...prev, [key]: value }));
}
const handleSelectMode = (key: string) => {
setSelectComponentListener((component) => {
if (component !== null) {
setData(prev => ({ ...prev, [key]: "${" + component.name + "}" }));
}
setSelectModeButton("");
})
setSelectModeButton(key);
activateSelectMode();
}
const validate = () => {
if (tableName === "") {
return false;
}
for (const key of Object.keys(data)) {
if (data[key] === "") {
return false;
}
}
return true;
}
const handleConfirm = () => {
const action: ButtonAddDataAction = {
tableName: tableName,
newData: data,
successScreenName: successScreen,
failScreenName: failScreen
}
const newComponent: ButtonComponent = { ...component, action: { type: "addData", action: action } };
updateComponent(-1, newComponent)
}
const changeCheck = () => {
if (!buttonAction) {
return false;
}
if (buttonAction.tableName !== tableName) {
return false;
}
for (const key of Object.keys(buttonAction.newData)) {
if (!(key in data)) {
return false;
}
if (data[key] !== buttonAction.newData[key]) {
return false;
}
}
if (buttonAction.successScreenName !== successScreen) {
return false;
}
if (buttonAction.failScreenName !== failScreen) {
return false;
}
return true;
}
return (
<div className="flex h-full min-h-0 flex-col overflow-y-auto">
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
テーブル
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={tableName}
onChange={handleTableChange}
>
<option value={""}>選択してください</option>
{tables.map((table, idx) => (
<option key={idx} value={table.name}>
{table.name}
</option>
))}
</select>
</div>
{tableName !== "" && <div className="flex-col">
{Object.keys(data).map((colName, idx) => (
<div key={`col${idx}2`} className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
{colName}
</label>
<div className="flex gap-4">
<input
type="text"
value={data[colName] ?? ""}
onChange={(e) => handleChange(colName, e.target.value)}
className="flex-6 w-full px-3 py-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
<button
onClick={() => handleSelectMode(colName)}
className={`flex-1 flex items-center border border-gray-300 justify-center
rounded-lg hover:bg-gray-300 hover:text-gray-900
transition ${selectModeButton === colName ? "bg-blue-500 text-gray-100" : "text-gray-600"}`}
>
<MdEdit />
</button>
</div>
</div>
))}
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
成功時スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={successScreen}
onChange={(e) => setSuccessScreen(e.target.value)}
>
<option value={""}>なし</option>
<option value="_back">戻る</option>
{screens.map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
失敗時スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={failScreen}
onChange={(e) => setFailScreen(e.target.value)}
>
<option value={""}>なし</option>
<option value="_back">戻る</option>
{screens.map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
</div>}
<div className="mb-4 flex justify-end">
<button
onClick={handleConfirm}
disabled={changeCheck() || !validate()}
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed rounded-lg transition-colors"
>
決定
</button>
</div>
</div>
)
}
interface UpdateDataPropertiesProps {
component: ButtonComponent
screens: Screen[]
tables: Table[]
updateComponent: (index: number, newComponent: Component) => void,
setSelectComponentListener: (listener: SelectComponentListenerType) => void
activateSelectMode: () => void
}
function UpdateDataProperties({
component,
screens,
tables,
updateComponent,
setSelectComponentListener,
activateSelectMode
}: UpdateDataPropertiesProps) {
const buttonAction =
(component.action?.type ?? "") === "updateData"
? component.action?.action as ButtonUpdateDataAction
: {
tableName: "",
newData: {},
failScreenName: "",
successScreenName: ""
};
const [tableName, setTableName] = useState<string>(buttonAction?.tableName ?? "");
const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.newData ?? {});
const [selectModeButton, setSelectModeButton] = useState<string>("");
const [successScreen, setSuccessScreen] = useState<string>(buttonAction?.successScreenName ?? "")
const [failScreen, setFailScreen] = useState<string>(buttonAction?.failScreenName ?? "")
const handleTableChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setTableName(e.target.value);
const res: { [key: string]: string } = {}
for (const col of tables.find((table) => table.name === e.target.value)?.columns ?? []) {
if (!col.foreignTableName) {
res[col.name] = "";
} else {
const ftable = tables.find((table) => table.name === col.foreignTableName);
for (const fcol of ftable?.columns ?? []) {
if (fcol.isPrimary) {
res[`${ftable?.name}.${fcol.name}`] = "";
}
}
}
}
setData(res);
setSuccessScreen("");
setFailScreen("");
}
const handleChange = (key: string, value: string) => {
setData(prev => ({ ...prev, [key]: value }));
}
const handleSelectMode = (key: string) => {
setSelectComponentListener((component) => {
if (component !== null) {
setData(prev => ({ ...prev, [key]: "${" + component.name + "}" }));
}
setSelectModeButton("");
})
setSelectModeButton(key);
activateSelectMode();
}
const validate = () => {
if (tableName === "") {
return false;
}
for (const key of Object.keys(data)) {
if (data[key] === "") {
return false;
}
}
return true;
}
const handleConfirm = () => {
const action: ButtonUpdateDataAction = {
tableName: tableName,
newData: data,
successScreenName: successScreen,
failScreenName: failScreen
}
const newComponent: ButtonComponent = { ...component, action: { type: "updateData", action: action } };
updateComponent(-1, newComponent)
}
const changeCheck = () => {
if (!buttonAction) {
return false;
}
if (buttonAction.tableName !== tableName) {
return false;
}
for (const key of Object.keys(buttonAction.newData)) {
if (!(key in data)) {
return false;
}
if (data[key] !== buttonAction.newData[key]) {
return false;
}
}
if (buttonAction.successScreenName !== successScreen) {
return false;
}
if (buttonAction.failScreenName !== failScreen) {
return false;
}
return true;
}
return (
<div className="flex-col overflow-y-auto">
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
テーブル
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={tableName}
onChange={handleTableChange}
>
<option value={""}>選択してください</option>
{tables.map((table, idx) => (
<option key={idx} value={table.name}>
{table.name}
</option>
))}
</select>
</div>
{tableName !== "" && <div className="flex-col">
{Object.keys(data).map((colName, idx) => (
<div key={`col${idx}2`} className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
{colName}
</label>
<div className="flex gap-4">
<input
type="text"
value={data[colName] ?? ""}
onChange={(e) => handleChange(colName, e.target.value)}
className="flex-6 w-full px-3 py-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
<button
onClick={() => handleSelectMode(colName)}
className={`flex-1 flex items-center border border-gray-300 justify-center
rounded-lg hover:bg-gray-300 hover:text-gray-900
transition ${selectModeButton === colName ? "bg-blue-500 text-gray-100" : "text-gray-600"}`}
>
<MdEdit />
</button>
</div>
</div>
))}
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
成功時スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={successScreen}
onChange={(e) => setSuccessScreen(e.target.value)}
>
<option value={""}>なし</option>
<option value="_back">戻る</option>
{screens.map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
失敗時スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={failScreen}
onChange={(e) => setFailScreen(e.target.value)}
>
<option value={""}>なし</option>
<option value="_back">戻る</option>
{screens.map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
</div>}
<div className="mb-4 flex justify-end">
<button
onClick={handleConfirm}
disabled={changeCheck() || !validate()}
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed rounded-lg transition-colors"
>
決定
</button>
</div>
</div>
)
}
interface DeleteDataPropertiesProps {
component: ButtonComponent
screens: Screen[]
tables: Table[]
updateComponent: (index: number, newComponent: Component) => void,
setSelectComponentListener: (listener: SelectComponentListenerType) => void
activateSelectMode: () => void
}
function DeleteDataProperties({
component,
screens,
tables,
updateComponent,
setSelectComponentListener,
activateSelectMode
}: DeleteDataPropertiesProps) {
const buttonAction =
(component.action?.type ?? "") === "deleteData"
? component.action?.action as ButtonDeleteDataAction
: {
tableName: "",
deleteData: {},
failScreenName: "",
successScreenName: ""
};
const [tableName, setTableName] = useState<string>(buttonAction?.tableName ?? "");
const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.deleteData ?? {});
const [selectModeButton, setSelectModeButton] = useState<string>("");
const [successScreen, setSuccessScreen] = useState<string>(buttonAction?.successScreenName ?? "")
const [failScreen, setFailScreen] = useState<string>(buttonAction?.failScreenName ?? "")
const handleTableChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setTableName(e.target.value);
const res: { [key: string]: string } = {}
for (const col of tables.find((table) => table.name === e.target.value)?.columns ?? []) {
if (col.isPrimary) {
res[col.name] = "";
}
}
setData(res);
setSuccessScreen("");
setFailScreen("");
}
const handleChange = (key: string, value: string) => {
setData(prev => ({ ...prev, [key]: value }));
}
const handleSelectMode = (key: string) => {
setSelectComponentListener((component) => {
if (component !== null) {
setData(prev => ({ ...prev, [key]: "${" + component.name + "}" }));
}
setSelectModeButton("");
})
setSelectModeButton(key);
activateSelectMode();
}
const validate = () => {
if (tableName === "") {
return false;
}
for (const key of Object.keys(data)) {
if (data[key] === "") {
return false;
}
}
return true;
}
const handleConfirm = () => {
const action: ButtonDeleteDataAction = {
tableName: tableName,
deleteData: data,
successScreenName: successScreen,
failScreenName: failScreen
}
const newComponent: ButtonComponent = { ...component, action: { type: "deleteData", action: action } };
updateComponent(-1, newComponent)
}
const changeCheck = () => {
if (!buttonAction) {
return false;
}
if (buttonAction.tableName !== tableName) {
return false;
}
for (const key of Object.keys(buttonAction.deleteData)) {
if (!(key in data)) {
return false;
}
if (data[key] !== buttonAction.deleteData[key]) {
return false;
}
}
if (buttonAction.successScreenName !== successScreen) {
return false;
}
if (buttonAction.failScreenName !== failScreen) {
return false;
}
return true;
}
return (
<div className="flex-col overflow-y-auto">
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
テーブル
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={tableName}
onChange={handleTableChange}
>
<option value={""}>選択してください</option>
{tables.map((table, idx) => (
<option key={idx} value={table.name}>
{table.name}
</option>
))}
</select>
</div>
{tableName !== "" && <div className="flex-col">
{Object.keys(data).map((colName, idx) => (
<div key={`col${idx}2`} className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
{colName}
</label>
<div className="flex gap-4">
<input
type="text"
value={data[colName] ?? ""}
onChange={(e) => handleChange(colName, e.target.value)}
className="flex-6 w-full px-3 py-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
<button
onClick={() => handleSelectMode(colName)}
className={`flex-1 flex items-center border border-gray-300 justify-center
rounded-lg hover:bg-gray-300 hover:text-gray-900
transition ${selectModeButton === colName ? "bg-blue-500 text-gray-100" : "text-gray-600"}`}
>
<MdEdit />
</button>
</div>
</div>
))}
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
成功時スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={successScreen}
onChange={(e) => setSuccessScreen(e.target.value)}
>
<option value={""}>なし</option>
<option value={"_back"}>戻る</option>
{screens.map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
失敗時スクリーン
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={failScreen}
onChange={(e) => setFailScreen(e.target.value)}
>
<option value={""}>なし</option>
<option value={"_back"}>戻る</option>
{screens.map((screen, idx) => (
<option key={idx} value={screen.name}>
{screen.name}
</option>
))}
</select>
</div>
</div>}
<div className="mb-4 flex justify-end">
<button
onClick={handleConfirm}
disabled={changeCheck() || !validate()}
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed rounded-lg transition-colors"
>
決定
</button>
</div>
</div>
)
}
interface SearchDataPropertiesProps {
component: ButtonComponent
tables: Table[]
updateComponent: (index: number, newComponent: Component) => void,
setSelectComponentListener: (listener: SelectComponentListenerType) => void
activateSelectMode: () => void
}
function SearchDataProperties({
component,
tables,
updateComponent,
setSelectComponentListener,
activateSelectMode
}: SearchDataPropertiesProps) {
const buttonAction =
(component.action?.type ?? "") === "searchData"
? component.action?.action as ButtonSearchDataAction
: {
tableName: "",
searchData: {},
targetComponentName: ""
} as ButtonSearchDataAction
const [tableName, setTableName] = useState<string>(buttonAction?.tableName ?? "");
const [selectableColumns, setSelectableColumns] = useState<string[]>(Object.keys(buttonAction?.searchData ?? {}));
const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.searchData ?? {});
const [selectModeButton, setSelectModeButton] = useState<string>("");
const [targetComponentId, setTargetComponentId] = useState<string>(buttonAction.targetComponentName ?? "");
const handleTableChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setTableName(e.target.value);
const res = [];
for (const col of tables.find((table) => table.name === e.target.value)?.columns ?? []) {
if (!col.isPrimary) {
if (!col.foreignTableName) {
res.push(col.name)
} else {
const table = tables.find((table) => table.name === col.foreignTableName);
for (const fcol of col.foreignTableColumns ?? []) {
res.push(`${table?.name}.${fcol}`)
}
}
}
}
console.log(res);
setSelectableColumns(res);
setData({});
}
const handleChange = (key: string, value: string) => {
setData(prev => ({ ...prev, [key]: value }));
}
const handleSelectMode = (key: string) => {
setSelectComponentListener((component) => {
if (component !== null) {
setData(prev => ({ ...prev, [key]: "${" + component.name + "}" }));
}
setSelectModeButton("");
})
setSelectModeButton(key);
activateSelectMode();
}
const handleTargetSelect = () => {
setSelectComponentListener((component) => {
if (component !== null) {
setTargetComponentId("${" + component.name + "}")
}
setSelectModeButton("");
})
setSelectModeButton("_____");
activateSelectMode();
}
const handleSelect = (colName: string) => {
if (colName in data) {
setData(prev => {
const res: { [key: string]: string } = {};
for (const key of Object.keys(prev)) {
if (key !== colName) {
res[key] = prev[key];
}
}
return res;
});
} else {
setData(prev => ({ ...prev, [colName]: "" }));
}
}
const validate = () => {
if (tableName === "") {
return false;
}
if (Object.keys(data).length === 0) {
return false;
}
for (const key of Object.keys(data)) {
if (data[key] === "") {
return false;
}
}
if (!targetComponentId.trim()) {
return false;
}
if (targetComponentId === "") {
return false;
}
return true;
}
const handleConfirm = () => {
const action: ButtonSearchDataAction = {
tableName: tableName,
searchData: data,
targetComponentName: targetComponentId
}
const newComponent: ButtonComponent = { ...component, action: { type: "searchData", action: action } };
updateComponent(-1, newComponent)
}
const changeCheck = () => {
if (!buttonAction) {
return false;
}
if (buttonAction.tableName !== tableName) {
return false;
}
for (const key of Object.keys(buttonAction.searchData)) {
if (!(key in data)) {
return false;
}
if (data[key] !== buttonAction.searchData[key]) {
return false;
}
}
if (buttonAction.targetComponentName !== targetComponentId) {
return false;
}
return true;
}
return (
<div className="flex-col overflow-y-auto">
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
テーブル
</label>
<select
className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
value={tableName}
onChange={handleTableChange}
>
<option value={""}>選択してください</option>
{tables.map((table, idx) => (
<option key={idx} value={table.name}>
{table.name}
</option>
))}
</select>
</div>
{tableName !== "" && <div className="flex-col">
{selectableColumns.map((colName, idx) => (
<div key={`col${idx}2`} className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
<input
type="checkbox"
className="mr-2"
checked={colName in data}
onChange={() => handleSelect(colName)}
/>
{colName}
</label>
<div className="flex gap-4">
<input
type="text"
value={data[colName] ?? ""}
onChange={(e) => handleChange(colName, e.target.value)}
readOnly={!(colName in data)}
className="flex-6 w-full px-3 py-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
<button
onClick={() => handleSelectMode(colName)}
disabled={!(colName in data)}
className={`flex-1 flex items-center border border-gray-300 justify-center
rounded-lg hover:bg-gray-300 hover:text-gray-900
transition ${selectModeButton === colName ? "bg-blue-500 text-gray-100" : "text-gray-600"}
${!(colName in data) && "hover:cursor-not-allowed"}
`}
>
<MdEdit />
</button>
</div>
</div>
))}
<div className="mb-4">
<label className="block font-medium text-gray-700 mb-2">
宛先テーブル
</label>
<div className="flex gap-4">
<input
type="text"
value={targetComponentId}
onChange={(e) => setTargetComponentId(e.target.value)}
className="flex-6 w-full px-3 py-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
<button
onClick={() => handleTargetSelect()}
className={`flex-1 flex items-center border border-gray-300 justify-center
rounded-lg hover:bg-gray-300 hover:text-gray-900
transition ${selectModeButton === "_____" ? "bg-blue-500 text-gray-100" : "text-gray-600"}
`}
>
<MdEdit />
</button>
</div>
</div>
</div>}
<div className="mb-4 flex justify-end">
<button
onClick={handleConfirm}
disabled={!validate() || changeCheck()}
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed rounded-lg transition-colors"
>
決定
</button>
</div>
</div>
)
}