import type { ButtonGeneralData, Component, GeneralData, TableGeneralData, TextFieldGeneralData, TextGeneralData, UIData } from "../types/component";
import { ComponentType } from "../types/component";
import type { Screen } from "../types/screen";
import { useCallback, useMemo, useRef, useState } from "react";
import type { Dispatch, SetStateAction } from "react";
export interface ComponentState {
selectingComponent: Component | null,
selectingComponentIndex: number,
curScreenComponents: Component[]
}
export type SelectComponentListenerType = (selected: Component | null) => void
export interface ComponentActions {
addComponent: (type: ComponentType) => void,
addComponents: (components: Component[], screenId: string) => void
moveComponent: (index: number, uiData: UIData) => void,
updateComponent: (index: number, newComponent: Component) => void,
deleteComponent: (index: number, id: string) => void,
setSelectComponentListener: (listner: SelectComponentListenerType) => void
selectComponent: (index: number) => void,
resetSelectingComponent: () => void,
activateSelectMode: () => void
}
export interface ComponentDispatch {
setSelectingComponentIndex: Dispatch<SetStateAction<number>>,
}
export interface ComponentStateAndActions {
componentState: ComponentState,
componentActions: ComponentActions,
componentDispatch: ComponentDispatch
}
export function useComponent(
curScreenIndex: number,
curScreen: Screen,
setScreens: Dispatch<SetStateAction<Screen[]>>
): ComponentStateAndActions {
const [selectingComponentIndex, setSelectingComponentIndex] = useState<number>(-1);
const [selectMode, setSelectMode] = useState<boolean>(false);
// const [selectComponentCallback, setSelectComponentCallback] = useState<SelectComponentListenerType | null>(null);
const selectComponentCallbackRef = useRef<SelectComponentListenerType | null>(null);
const curScreenComponents: Component[] = useMemo(() => curScreen.components, [curScreen])
const selectingComponent: Component | null = useMemo(() => {
if (selectingComponentIndex === -1) {
return null;
}
return curScreenComponents[selectingComponentIndex]
}, [curScreenComponents, selectingComponentIndex]);
function getInitialGeneralData(type: ComponentType): GeneralData {
switch (type) {
case ComponentType.Text:
return { text: "text" }
case ComponentType.Button:
return { text: "button" }
case ComponentType.TextField:
return { text: "text field" }
case ComponentType.Table:
return { referenceTableName: "", columns: [] }
}
}
const addComponent = async (type: ComponentType) => {
let nextIndex = 0;
if (curScreenComponents.length > 0) {
nextIndex = curScreenComponents[curScreenComponents.length - 1].index + 1;
}
const uiData: UIData = {
posX: 100,
posY: 100,
width: 75,
height: 25
}
const newId = "w" + self.crypto.randomUUID().replace(/-/g, "")
let newComponent: Component;
switch (type) {
case ComponentType.Button:
newComponent = {
id: newId,
name: newId,
type: type,
index: nextIndex,
screenId: curScreen.id,
generalData: getInitialGeneralData(type) as ButtonGeneralData,
style: {},
uiData: uiData,
}
break;
case ComponentType.Text:
newComponent = {
id: newId,
name: newId,
type: type,
index: nextIndex,
screenId: curScreen.id,
generalData: getInitialGeneralData(type) as TextGeneralData,
style: {},
uiData: uiData,
}
break;
case ComponentType.TextField:
newComponent = {
id: newId,
name: newId,
type: type,
index: nextIndex,
screenId: curScreen.id,
generalData: getInitialGeneralData(type) as TextFieldGeneralData,
style: {},
uiData: uiData,
}
break;
case ComponentType.Table:
newComponent = {
id: newId,
name: newId,
type: type,
index: nextIndex,
screenId: curScreen.id,
generalData: getInitialGeneralData(type) as TableGeneralData,
style: {},
uiData: uiData,
}
break;
}
setScreens(screens => screens.map((screen, i) =>
i === curScreenIndex ? {
...screen,
components: [...screen.components, newComponent]
} : screen
));
// await fetch(`/api/projects/${curScreen.projectId}/screens/${curScreen.id}/components`, {
// method: "POST",
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({
// newComponents: [newComponent],
// }),
// });
}
const addComponents = async (components: Component[], screenId: string) => {
setScreens(screens => screens.map((screen) =>
screen.id === screenId ? {
...screen,
components: [...screen.components, ...components]
} : screen
));
// await fetch(`/api/projects/${curScreen.projectId}/screens/${screenId}/components`, {
// method: "POST",
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({
// newComponents: components,
// }),
// });
}
const moveComponent = async (index: number, uiData: UIData) => {
if (!selectingComponent) return;
setScreens(screens => screens.map((screen, i) =>
i === curScreenIndex ? {
...screen,
components: screens[i].components.map((comp, j) => j === index ? { ...comp, uiData: uiData } : comp)
} : screen
));
// await fetch(`/api/projects/${curScreen.projectId}/screens/${curScreen.id}/components/${selectingComponent.id}/uiData`, {
// method: "PUT",
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify({ uiData: uiData }),
// });
}
const deleteComponent = async (index: number) => {
setScreens((prev) => (prev.map((screen, scrIdx) => scrIdx === curScreenIndex ? {
...screen,
components: screen.components.filter((_, compIdx) => compIdx !== index)
} : screen)));
// await fetch(`/api/projects/${curScreen.projectId}/screens/${curScreen.id}/components/${id}`, {
// method: "DELETE",
// });
}
const updateComponent = (index: number, newComponent: Component) => {
if (index == -1) { //-1の時は現在選択中のコンポーネント
index = selectingComponentIndex
}
console.log(newComponent);
setScreens(screens => screens.map((screen, i) =>
i === curScreenIndex ? {
...screen,
components: screens[i].components.map((comp, j) => j === index ? newComponent : comp)
} : screen
));
}
const setSelectComponentListener = useCallback((listener: SelectComponentListenerType) => {
selectComponentCallbackRef.current = listener;
}, [])
const selectComponent = (index: number) => {
if (selectMode) {
selectComponentCallbackRef.current?.(curScreenComponents[index]);
selectComponentCallbackRef.current = null;
setSelectMode(false);
} else {
setSelectingComponentIndex(index);
}
}
const resetSelectingComponent = () => {
if (selectMode) {
selectComponentCallbackRef.current?.(null);
selectComponentCallbackRef.current = null;
setSelectMode(false);
} else {
setSelectingComponentIndex(-1);
}
}
const activateSelectMode = () => {
setSelectMode(true);
}
return {
componentState: {
selectingComponent,
selectingComponentIndex,
curScreenComponents
},
componentActions: {
addComponent,
addComponents,
deleteComponent,
moveComponent,
updateComponent,
setSelectComponentListener,
selectComponent,
resetSelectingComponent,
activateSelectMode
},
componentDispatch: {
setSelectingComponentIndex
}
}
}