Skip to content

Commit

Permalink
refactor(web): infobox's customized property list. (#1317)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkumbobeaty authored Dec 17, 2024
1 parent e361437 commit ec01d9f
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
import { Button, Icon, TextInput } from "@reearth/beta/lib/reearth-ui";
import { useT } from "@reearth/services/i18n";
import { styled } from "@reearth/services/theme";
import { styled, useTheme } from "@reearth/services/theme";
import { FC, useCallback, useState } from "react";

import { PropertyListItem } from ".";

type Props = {
item: PropertyListItem;
isEditKey: boolean;
isEditValue: boolean;
handleClassName?: string;
onKeyBlur: (newValue?: string) => void;
onValueBlur: (newValue?: string) => void;
onItemRemove: () => void;
onDoubleClick?: (field: string) => void;
};

const EditorItem: FC<Props> = ({
item,
handleClassName,
isEditKey,
isEditValue,
onKeyBlur,
onValueBlur,
onItemRemove
onItemRemove,
onDoubleClick
}) => {
const [currentKeyValue, setCurrentKeyValue] = useState<string>(item.key);
const [currentValue, setCurrentValue] = useState<string>(item.value);
const t = useT();
const theme = useTheme();

const [currentKeyItem, setCurrentKeyItem] = useState<string>(item.key);
const [currentValueItem, setCurrentValueItem] = useState<string>(item.value);

const handleKeyChange = useCallback((newValue: string) => {
setCurrentKeyValue(newValue);
setCurrentKeyItem(newValue);
}, []);

const handleKeyBlur = useCallback(
Expand All @@ -35,7 +44,7 @@ const EditorItem: FC<Props> = ({
);

const handleValueChange = useCallback((newValue: string) => {
setCurrentValue(newValue);
setCurrentValueItem(newValue);
}, []);

const handleValueBlur = useCallback(
Expand All @@ -45,25 +54,45 @@ const EditorItem: FC<Props> = ({
[onValueBlur]
);

const t = useT();

return (
<Field>
<HandleIcon icon="dotsSixVertical" className={handleClassName} />
<TextInput
size="small"
value={currentKeyValue}
placeholder={t("Display title")}
onChange={handleKeyChange}
onBlur={handleKeyBlur}
/>
<TextInput
<Icon
className={handleClassName}
icon="dotsSixVertical"
color={theme.content.weak}
size="small"
value={currentValue}
placeholder={t("${your property name}")}
onChange={handleValueChange}
onBlur={handleValueBlur}
/>
<ItemCol>
{item.key === "" || isEditKey ? (
<TextInput
size="small"
value={currentKeyItem}
placeholder={t("Display title")}
onChange={handleKeyChange}
onBlur={handleKeyBlur}
/>
) : (
<TextWrapper onDoubleClick={() => onDoubleClick?.("key")}>
{currentKeyItem}
</TextWrapper>
)}
</ItemCol>
<ItemCol>
{item.value === "" || isEditValue ? (
<TextInput
size="small"
value={currentValueItem}
placeholder={t("${your property name}")}
onChange={handleValueChange}
onBlur={handleValueBlur}
/>
) : (
<TextWrapper onDoubleClick={() => onDoubleClick?.("value")}>
{currentValueItem}
</TextWrapper>
)}
</ItemCol>

<Button
icon="trash"
iconButton
Expand All @@ -89,10 +118,16 @@ const Field = styled("div")(({ theme }) => ({
borderRadius: theme.radius.smallest
}));

const HandleIcon = styled(Icon)(({ theme }) => ({
color: theme.content.weak,
cursor: "move",
"&:hover": {
color: theme.content.main
}
const ItemCol = styled("div")(() => ({
flex: 1
}));

const TextWrapper = styled("div")(({ theme }) => ({
color: theme.content.main,
fontSize: theme.fonts.sizes.body,
fontWeight: theme.fonts.weight.regular,
padding: theme.spacing.micro,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap"
}));
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isEqual } from "lodash-es";
import { useCallback, useEffect, useState } from "react";

import type { DisplayTypeField, PropertyListField } from ".";
Expand Down Expand Up @@ -31,6 +30,8 @@ export default ({
propertyListField?.value ?? []
);
const [isDragging, setIsDragging] = useState(false);
const [editKeyIndex, setEditKeyIndex] = useState<number | null>(null);
const [editValueIndex, setEditValueIndex] = useState<number | null>(null);

const displayOptions = displayTypeField?.choices?.map(
({ key, title }: { key: string; title: string }) => ({
Expand All @@ -39,15 +40,6 @@ export default ({
})
);

useEffect(() => {
if (
propertyListField?.value &&
!isEqual(propertyListField.value, currentPropertyList)
) {
setCurrentPropertyList(propertyListField?.value);
}
}, [propertyListField?.value, currentPropertyList]);

const handlePropertyValueUpdate = useCallback(
(fieldId?: string, vt?: any, itemId?: string) => {
return async (v?: any) => {
Expand All @@ -58,22 +50,24 @@ export default ({
[propertyId, onPropertyUpdate]
);

useEffect(() => {
setCurrentPropertyList(propertyListField?.value ?? []);
}, [propertyListField?.value]);

const handlePropertyValueRemove = useCallback(
async (idx: number) => {
if (propertyListField) {
const newValue = propertyListField.value?.filter((_, i) => i !== idx);
await handlePropertyValueUpdate(
"propertyList",
propertyListField.type
)(newValue);
}
(idx: number) => {
if (!currentPropertyList) return;
const updatedPropertiesList = [...currentPropertyList];
updatedPropertiesList.splice(idx, 1);
setCurrentPropertyList?.(updatedPropertiesList);
},
[propertyListField, handlePropertyValueUpdate]
[currentPropertyList]
);

const handlePropertyListUpdate = useCallback(
(newList: ListItem[]) =>
handlePropertyValueUpdate("propertyList", "array")(newList),

[handlePropertyValueUpdate]
);

Expand All @@ -82,19 +76,19 @@ export default ({
const newList = currentPropertyList.map((i) => ({ ...i }) as ListItem);
newList[idx].key = newKeyValue ?? "";
setCurrentPropertyList(newList);
handlePropertyListUpdate(newList);
if (editKeyIndex === idx) setEditKeyIndex(null);
},
[currentPropertyList, handlePropertyListUpdate]
[currentPropertyList, editKeyIndex]
);

const handleValueBlur = useCallback(
(idx: number) => (newValue?: string) => {
const newList = currentPropertyList.map((i) => ({ ...i }) as ListItem);
newList[idx].value = newValue ?? "";
setCurrentPropertyList(newList);
handlePropertyListUpdate(newList);
if (editValueIndex === idx) setEditValueIndex(null);
},
[currentPropertyList, handlePropertyListUpdate]
[currentPropertyList, editValueIndex]
);

const handleDisplayTypeUpdate = useCallback(
Expand All @@ -113,15 +107,15 @@ export default ({
value: ""
}
];
handlePropertyValueUpdate("propertyList", propertyListField.type)(newList);
}, [currentPropertyList, propertyListField, handlePropertyValueUpdate]);
setCurrentPropertyList(newList);
}, [currentPropertyList, propertyListField]);

const handleMoveStart = useCallback(() => {
setIsDragging(true);
}, []);

const handleItemDrop = useCallback(
async (
(
item: {
id: string;
key: string;
Expand All @@ -138,16 +132,8 @@ export default ({
newList.splice(itemIndex, 1);
newList.splice(targetIndex, 0, item);
setCurrentPropertyList(newList);
await onPropertyUpdate?.(
propertyId,
"default",
"propertyList",
undefined,
"array",
newList
);
},
[currentPropertyList, onPropertyUpdate, propertyId]
[currentPropertyList]
);

const handleMoveEnd = useCallback(
Expand All @@ -165,17 +151,31 @@ export default ({
[currentPropertyList, handleItemDrop]
);

const handleDoubleClick = useCallback((idx: number, field: string) => {
if (field === "key") {
setEditKeyIndex(idx);
setEditValueIndex(null);
} else if (field === "value") {
setEditValueIndex(idx);
setEditKeyIndex(null);
}
}, []);

return {
displayOptions,
currentPropertyList,
isDragging,
editValueIndex,
editKeyIndex,
handleKeyBlur,
handleValueBlur,
handleDisplayTypeUpdate,
handleItemAdd,
handlePropertyValueRemove,
handleMoveStart,
handleMoveEnd
handleMoveEnd,
handleDoubleClick,
handlePropertyListUpdate
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,17 @@ const ListEditor: FC<Props> = ({
const {
displayOptions,
currentPropertyList,
editValueIndex,
editKeyIndex,
handleKeyBlur,
handleValueBlur,
handleDisplayTypeUpdate,
handleItemAdd,
handleMoveStart,
handleMoveEnd,
handlePropertyValueRemove
handlePropertyValueRemove,
handleDoubleClick,
handlePropertyListUpdate
} = useHooks({
propertyId,
propertyListField,
Expand All @@ -92,19 +96,17 @@ const ListEditor: FC<Props> = ({
<EditorItem
key={item.id}
item={item}
isEditKey={editKeyIndex === idx}
isEditValue={editValueIndex === idx}
onKeyBlur={handleKeyBlur(idx)}
handleClassName={CURRENT_PROPERTY_LIST_DRAG_HANDLE_CLASS_NAME}
onValueBlur={handleValueBlur(idx)}
onDoubleClick={(field: string) => handleDoubleClick(idx, field)}
onItemRemove={() => handlePropertyValueRemove(idx)}
/>
)
})),
[
currentPropertyList,
handleKeyBlur,
handleValueBlur,
handlePropertyValueRemove
]
[currentPropertyList, editKeyIndex, editValueIndex, handleKeyBlur, handleValueBlur, handleDoubleClick, handlePropertyValueRemove]
);

return (
Expand All @@ -131,13 +133,22 @@ const ListEditor: FC<Props> = ({
</>
)}
{displayTypeField?.value === "custom" && (
<Button
title={t("New Field")}
icon="plus"
size="small"
onClick={handleItemAdd}
extendWidth
/>
<ActionsWrapper>
<Button
title={t("New Field")}
icon="plus"
size="small"
onClick={handleItemAdd}
extendWidth
/>
<Button
title={t("Save")}
icon="floppyDisk"
size="small"
onClick={() => handlePropertyListUpdate(currentPropertyList)}
extendWidth
/>
</ActionsWrapper>
)}
</Wrapper>
);
Expand All @@ -158,6 +169,12 @@ const FieldWrapper = styled("div")(({ theme }) => ({
flexDirection: "column",
justifyContent: "space-between",
gap: theme.spacing.smallest,
alignItems: "center",
boxsizing: "border-box"
boxSizing: "border-box"
}));

const ActionsWrapper = styled("div")(({ theme }) => ({
display: "flex",
gap: theme.spacing.smallest,
alignItems: "center",
boxSizing: "border-box"
}));

0 comments on commit ec01d9f

Please sign in to comment.