Skip to content

Instantly share code, notes, and snippets.

@topspinppy
Created August 31, 2023 07:44
Show Gist options
  • Save topspinppy/4d79836d9bb40692fdb437e638a61da2 to your computer and use it in GitHub Desktop.
Save topspinppy/4d79836d9bb40692fdb437e638a61da2 to your computer and use it in GitHub Desktop.
TabForm
function TabForm(props: ITabFormProps) {
const {
tab: defaultTab,
id,
handleMoveTask,
itemName,
minimumTabs,
index,
onChangeTitle,
onDiscard,
onEditTab,
onDeleteTab,
} = props;
const ItemTypes = {
CARD: 'card-tab',
};
const tabRef = useRef<HTMLDivElement>(null);
const localTabForm = useForm({ mode: 'all', defaultValues: transformTabToDefaultValue(defaultTab) });
const formValue = localTabForm.watch();
const [openDeleteTabDialog, setOpenDeleteTabDialog] = useState(false);
const [tempDeleteTabId, setTempDeleteTabId] = useState<string>('');
useEffect(() => {
localTabForm.setValue('id', defaultTab.id);
localTabForm.setValue('order', defaultTab.order);
localTabForm.setValue('status', defaultTab.status);
localTabForm.setValue('titleEN', defaultTab.titleEN);
localTabForm.setValue('titleTH', defaultTab.titleTH);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultTab.status]);
const onSubmit = async () => {
const formValid = await localTabForm.trigger();
if (!formValid) return;
const newTab = localTabForm.getValues();
onChangeTitle(newTab.id, newTab.titleTH, newTab.titleEN);
};
const renderTabTitle = (title: string) => {
const isTruncate = (text: string, maxLength = 20) => {
return text.length > maxLength;
};
if (isTruncate(title)) {
return (
<Tooltip title={title}>
<Typography variant="subtitle1" noWrap={true}>
{title}
</Typography>
</Tooltip>
);
}
return <Typography variant="subtitle1">{title}</Typography>;
};
const [, drop] = useDrop<DragItem, void>({
accept: ItemTypes.CARD,
canDrop(item, monitor) {
console.log(item, monitor.canDrop());
return monitor.canDrop();
},
hover(item: DragItem, monitor) {
console.log(item);
if (!tabRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) {
return;
}
const hoverBoundingRect = tabRef.current?.getBoundingClientRect();
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
handleMoveTask(dragIndex, hoverIndex);
item.index = hoverIndex;
},
});
const [{ isDragging }, drag] = useDrag({
type: ItemTypes.CARD,
item: () => {
return { id, index };
},
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
end(draggedItem, monitor) {
console.log(draggedItem);
},
});
drag(drop(tabRef));
return (
<Box
ref={tabRef}
bgcolor={(props) => props.palette.grey[100]}
borderRadius="0.3rem"
padding="1rem 0.5rem"
mt={index !== 0 ? '1rem' : undefined}
>
<Box display="flex">
<SvgIconStyle
src="/icons/ic_drag_dot.svg"
sx={{
position: 'relative',
top: '2px',
marginRight: '12px',
width: '24px',
height: '24px',
cursor: 'move',
}}
/>
<When condition={formValue.status === 'confirmed'}>
<Box flexGrow="6" width="7.5rem" display="flex" alignItems="center">
{renderTabTitle(`${formValue.titleTH} / ${formValue.titleEN}`)}
</Box>
<Box>
{/* ═══════════════ Edit Tab Button ═══════════════ */}
<IconButton
disableFocusRipple={true}
disableTouchRipple={true}
onClick={() => {
onEditTab(formValue.id);
}}
>
<SvgIconStyle
src={`/icons/ic_edit.svg`}
sx={{
width: '14px',
height: '14px',
}}
/>
</IconButton>
<IconButton
disableFocusRipple={true}
disableTouchRipple={true}
onClick={() => {
setOpenDeleteTabDialog(true);
setTempDeleteTabId(formValue.id);
}}
>
<SvgIconStyle src="/icons/ic_trash.svg" sx={{ width: '16px', height: '16px' }} />
</IconButton>
</Box>
</When>
<When condition={formValue.status === 'initial' || formValue.status === 'existing'}>
<Box flexGrow="6" width="7.5rem" display="flex" alignItems="center">
<Typography variant="subtitle1">Tab Name</Typography>
</Box>
<IconButton
disableFocusRipple
disableTouchRipple
onClick={() => {
const tabId = localTabForm.getValues('id');
onDiscard(tabId);
}}
>
<SvgIconStyle
src="/icons/ic_close.svg"
sx={{
width: '14px',
height: '14px',
color: (props) => props.palette.error.main,
}}
/>
</IconButton>
{/* ═══════════════ Check button ═══════════════ */}
<IconButton
disableFocusRipple
disableTouchRipple
onClick={() => {
onSubmit();
}}
>
<SvgIconStyle
src="/icons/ic_checkmark.svg"
sx={{
width: '16px',
height: '16px',
color: (props) => props.palette.success.main,
}}
/>
</IconButton>
</When>
</Box>
<When condition={formValue.status === 'initial' || formValue.status === 'existing'}>
<Box mt="1rem">
<Stack spacing={1.5}>
<Controller
control={localTabForm.control}
name="titleTH"
rules={{ required: `${itemName} Name (TH) is required.` }}
render={({ field, fieldState: { error } }) => {
const validationProps = error && {
error: true,
helperText: error?.message,
};
return (
<TextField
{...validationProps}
fullWidth
placeholder={`${itemName} Name (TH)`}
sx={{ mr: 1, fontWeight: 'fontWeightBold' }}
value={field.value}
inputProps={{ maxLength: 200 }}
onChange={(event) => {
field.onChange(event.target.value);
}}
/>
);
}}
/>
<Controller
control={localTabForm.control}
name="titleEN"
rules={{
required: `${itemName} Name (EN) is required.`,
}}
render={({ field, fieldState: { error } }) => {
const validationProps = error && {
error: true,
helperText: error?.message,
};
return (
<TextField
{...validationProps}
fullWidth
placeholder={`${itemName} Name (EN)`}
sx={{ mr: 1, fontWeight: 'fontWeightBold' }}
inputProps={{ maxLength: 200 }}
value={field.value}
onChange={(event) => {
field.onChange(event.target.value);
}}
/>
);
}}
/>
</Stack>
</Box>
</When>
<DeleteTabsDialog
open={openDeleteTabDialog}
onClose={() => setOpenDeleteTabDialog(false)}
onClick={() => {
onDeleteTab(tempDeleteTabId);
setOpenDeleteTabDialog(false);
setTempDeleteTabId('');
}}
/>
</Box>
);
}
export default observer(TabForm);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment