From 8000fd56db1127e102edd3d44e324069950abc5e Mon Sep 17 00:00:00 2001 From: aliraza556 Date: Fri, 10 Jan 2025 19:46:00 +0500 Subject: [PATCH 1/2] fix(refactor): update node request structure and types --- .../EditNodeNameModal/Body/index.tsx | 18 ++++++++++++------ src/types/index.ts | 4 +++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/ModalsContainer/EditNodeNameModal/Body/index.tsx b/src/components/ModalsContainer/EditNodeNameModal/Body/index.tsx index 5abb8288d..581307b28 100644 --- a/src/components/ModalsContainer/EditNodeNameModal/Body/index.tsx +++ b/src/components/ModalsContainer/EditNodeNameModal/Body/index.tsx @@ -9,7 +9,7 @@ import { getTopicsData, putNodeData } from '~/network/fetchSourcesData' import { useDataStore } from '~/stores/useDataStore' import { useSelectedNode } from '~/stores/useGraphStore' import { useModal } from '~/stores/useModalStore' -import { NodeExtended, Topic } from '~/types' +import { NodeExtended, NodeRequest, Topic } from '~/types' import { colors } from '~/utils/colors' import { TitleEditor } from '../Title' @@ -88,13 +88,13 @@ export const Body = () => { const updatedData = getValues() - const nodeData = { + const nodeData: NodeRequest = { node_type: node?.node_type, - node_data: { + properties: { name: updatedData.name, - properties: updatedData.properties, - ref_id: updatedData.ref_id, + ...(updatedData.properties as Record), }, + ref_id: node?.ref_id, } try { @@ -102,7 +102,13 @@ export const Body = () => { const { updateNode } = useDataStore.getState() - updateNode({ ...node, ...nodeData.node_data } as NodeExtended) + const updatedNode: NodeExtended = { + ...node, + name: nodeData.properties.name || '', + properties: nodeData.properties, + } as NodeExtended + + updateNode(updatedNode) closeHandler() } catch (error) { diff --git a/src/types/index.ts b/src/types/index.ts index 3df5b7400..90b1b0e0f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -110,12 +110,14 @@ export type RadarRequest = { export type NodeRequest = { node_type?: string - node_data: { + properties: { name?: string is_muted?: boolean topic?: string image_url?: string + [key: string]: unknown } + ref_id?: string } export type DataSeriesNode = { From 4f82a8a2d1b0b0f11826a549469e45be423f031e Mon Sep 17 00:00:00 2001 From: aliraza556 Date: Fri, 10 Jan 2025 19:59:10 +0500 Subject: [PATCH 2/2] fix(error): errors --- .../Topics/EditTopicModal/index.tsx | 196 +++---- .../SourcesView/Topics/Table/TableRow.tsx | 499 +++++++++--------- .../SourcesView/Topics/index.tsx | 5 +- 3 files changed, 354 insertions(+), 346 deletions(-) diff --git a/src/components/SourcesTableModal/SourcesView/Topics/EditTopicModal/index.tsx b/src/components/SourcesTableModal/SourcesView/Topics/EditTopicModal/index.tsx index 03879bba1..07442c0f8 100644 --- a/src/components/SourcesTableModal/SourcesView/Topics/EditTopicModal/index.tsx +++ b/src/components/SourcesTableModal/SourcesView/Topics/EditTopicModal/index.tsx @@ -1,97 +1,99 @@ -import { Button } from '@mui/material' -import { FC, useEffect, useState } from 'react' -import { FormProvider, useForm } from 'react-hook-form' -import { ClipLoader } from 'react-spinners' -import { BaseModal } from '~/components/Modal' -import { putNodeData } from '~/network/fetchSourcesData' -import { useModal } from '~/stores/useModalStore' -import { useTopicsStore } from '~/stores/useTopicsStore' -import { Topic } from '~/types' -import { colors } from '~/utils/colors' -import { TitleEditor } from './Title' -import styled from 'styled-components' - -type Props = { - topic: Topic - onClose: () => void -} - -export type FormData = { - name: string -} - -export const EditTopicModal: FC = ({ topic, onClose }) => { - const { close } = useModal('editTopic') - const [data] = useTopicsStore((s) => [s.data]) - const form = useForm({ mode: 'onChange' }) - const { watch, setValue, reset, getValues } = form - const [loading, setLoading] = useState(false) - - useEffect(() => { - if (topic) { - setValue('name', topic?.name) - } - - return () => { - reset() - } - }, [topic, setValue, reset]) - - const nameValue = watch('name') - const name = nameValue?.trim() - - const closeHandler = () => { - onClose() - close() - } - - const handleSave = async () => { - setLoading(true) - - try { - await putNodeData(topic?.ref_id, { node_type: topic?.node_type, node_data: { name } }) - - if (data) { - const newData = { ...data } - - newData[topic?.ref_id].name = name - - useTopicsStore.setState({ data: newData }) - } - - closeHandler() - } catch (error) { - console.warn(error) - } finally { - setLoading(false) - } - } - - const isTopicNameChanged = getValues().name && topic?.name !== getValues().name - - return ( - - - - - - - ) -} - -const ClipLoaderWrapper = styled.span` - margin-top: 2px; -` +import { Button } from '@mui/material' +import { FC, useEffect, useState } from 'react' +import { FormProvider, useForm } from 'react-hook-form' +import { ClipLoader } from 'react-spinners' +import styled from 'styled-components' +import { BaseModal } from '~/components/Modal' +import { putNodeData } from '~/network/fetchSourcesData' +import { useModal } from '~/stores/useModalStore' +import { useTopicsStore } from '~/stores/useTopicsStore' +import { Topic } from '~/types' +import { colors } from '~/utils/colors' +import { TitleEditor } from './Title' + +type Props = { + topic: Topic + onClose: () => void +} + +export type FormData = { + name: string +} + +export const EditTopicModal: FC = ({ topic, onClose }) => { + const { close } = useModal('editTopic') + const [data] = useTopicsStore((s) => [s.data]) + const form = useForm({ mode: 'onChange' }) + const { watch, setValue, reset, getValues } = form + const [loading, setLoading] = useState(false) + + useEffect(() => { + if (topic) { + setValue('name', topic?.name) + } + + return () => { + reset() + } + }, [topic, setValue, reset]) + + const nameValue = watch('name') + const name = nameValue?.trim() + + const closeHandler = () => { + onClose() + close() + } + + const handleSave = async () => { + setLoading(true) + + try { + await putNodeData(topic?.ref_id, { + node_type: topic?.node_type, + properties: { name } + }) + + if (data) { + const newData = { ...data } + + newData[topic?.ref_id].name = name + useTopicsStore.setState({ data: newData }) + } + + closeHandler() + } catch (error) { + console.warn(error) + } finally { + setLoading(false) + } + } + + const isTopicNameChanged = getValues().name && topic?.name !== getValues().name + + return ( + + + + + + + ) +} + +const ClipLoaderWrapper = styled.span` + margin-top: 2px; +` diff --git a/src/components/SourcesTableModal/SourcesView/Topics/Table/TableRow.tsx b/src/components/SourcesTableModal/SourcesView/Topics/Table/TableRow.tsx index a655d6738..f510efd41 100644 --- a/src/components/SourcesTableModal/SourcesView/Topics/Table/TableRow.tsx +++ b/src/components/SourcesTableModal/SourcesView/Topics/Table/TableRow.tsx @@ -1,248 +1,251 @@ -import { IconButton, Popover, Typography } from '@mui/material' -import React, { FC, memo, useState } from 'react' -import { ClipLoader } from 'react-spinners' -import styled from 'styled-components' -import CheckIcon from '~/components/Icons/CheckIcon' -import ProfileHide from '~/components/Icons/PropertyHide' -import ProfileShow from '~/components/Icons/PropertyShow' -import ThreeDotsIcons from '~/components/Icons/ThreeDotsIcons' -import { Flex } from '~/components/common/Flex' -import { putNodeData } from '~/network/fetchSourcesData' -import { useTopicsStore } from '~/stores/useTopicsStore' -import { Topic } from '~/types' -import { formatDate } from '~/utils' -import { colors } from '~/utils/colors' -import { StyledTableCell, StyledTableRow } from '../../common' - -type TTableRaw = { - topic: Topic - onClick: (event: React.MouseEvent, refId: string) => void - onSearch: (search: string) => void - checkedStates: { [refId: string]: boolean } - setCheckedStates: React.Dispatch> - isMuteDisabled?: boolean -} - -interface CheckboxIconProps { - checked?: boolean -} - -const TableRowComponent: FC = ({ - topic, - onClick, - onSearch, - checkedStates, - setCheckedStates, - isMuteDisabled, -}) => { - const [ids, total] = useTopicsStore((s) => [s.ids, s.total]) - const [loading, setLoading] = useState(false) - const [isPopoverOpen, setIsPopoverOpen] = useState(false) - - const date = formatDate(topic.date_added_to_graph) - - const handleMute = async (refId: string, shouldMute: boolean) => { - setLoading(true) - - try { - await putNodeData(refId, { node_type: topic?.node_type, node_data: { is_muted: shouldMute } }) - - useTopicsStore.setState({ - ids: ids.filter((i) => i !== refId), - total: total - 1, - }) - } catch (error) { - console.warn(error) - } - } - - const handleSelect = (refId: string) => { - setCheckedStates((prev) => ({ - ...prev, - [refId]: !prev[refId], - })) - } - - const handleClickTopic = (event: React.MouseEvent, topicItem: Topic) => { - if (window.getSelection()?.toString()) { - event.preventDefault() - } else { - onSearch(topicItem.name) - } - } - - const lettersToShow = topic.edgeList.slice(0, 1) - const hiddenLettersCount = topic.edgeList.length - lettersToShow.length - - const [anchorEl, setAnchorEl] = React.useState(null) - - const handlePopoverOpen = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget) - setIsPopoverOpen(true) - } - - const handlePopoverClose = () => { - setIsPopoverOpen(false) - } - - const open = Boolean(anchorEl) && isPopoverOpen - - const checkboxVisibleClass = checkedStates[topic.ref_id] ? 'visible' : '' - - return ( - - - handleSelect(topic.ref_id)} - > - - {checkedStates[topic.ref_id] && } - - - - handleClickTopic(event, topic)}> - {topic.name} - - {topic.node_type} - - {topic.edgeCount} - - - setIsPopoverOpen(true)} - onMouseLeave={handlePopoverClose} - open={open} - sx={{ - pointerEvents: 'auto', - '& .MuiPaper-root': { - backgroundColor: 'rgba(0, 0, 0, 0.9)', - borderRadius: '4px', - width: '160px', - maxHeight: '200px', - overflowY: 'scroll', - }, - }} - transformOrigin={{ - vertical: 'bottom', - horizontal: 'center', - }} - > - - {topic.edgeList.join(', ')} - - - {lettersToShow.join(', ')} - {hiddenLettersCount > 0 && ( - - ,... - - )} - - - {date} - - - - -
- {loading ? ( - - - - ) : ( - - {topic.is_muted ? ( - handleMute(topic.ref_id, false)} - > - - - ) : ( - handleMute(topic.ref_id, true)} - > - - - )} - onClick(e, topic.ref_id)}> - - - - )} -
-
-
-
- ) -} - -const ClipLoaderWrapper = styled.span` - margin-left: 12px; -` - -const ClickableText = styled.span` - cursor: pointer; - :hover { - text-decoration: underline; - } -` - -const CheckboxSection = styled.td` - visibility: hidden; - cursor: pointer; - display: flex; - align-items: center; - - &.visible { - visibility: visible; - } -` - -const CheckboxIcon = styled.div` - width: 14px; - height: 14px; - border-radius: 4px; - border: ${({ checked }) => (checked ? '#618AFF' : '2px solid #CCCCCC')}; - background-color: ${({ checked }) => (checked ? '#618AFF' : 'transparent')}; - display: flex; - justify-content: center; - align-items: center; - margin-left: 12px; -` - -const Checkmark = styled.div` - display: flex; - align-items: center; - justify-content: center; - border-radius: 2px; - background-color: transparent; -` - -const CountEdgeWrapper = styled.span` - display: flex; - align-items: center; - justify-content: center; -` - -export const TopicRow = memo(TableRowComponent) +import { IconButton, Popover, Typography } from '@mui/material' +import React, { FC, memo, useState } from 'react' +import { ClipLoader } from 'react-spinners' +import styled from 'styled-components' +import CheckIcon from '~/components/Icons/CheckIcon' +import ProfileHide from '~/components/Icons/PropertyHide' +import ProfileShow from '~/components/Icons/PropertyShow' +import ThreeDotsIcons from '~/components/Icons/ThreeDotsIcons' +import { Flex } from '~/components/common/Flex' +import { putNodeData } from '~/network/fetchSourcesData' +import { useTopicsStore } from '~/stores/useTopicsStore' +import { Topic } from '~/types' +import { formatDate } from '~/utils' +import { colors } from '~/utils/colors' +import { StyledTableCell, StyledTableRow } from '../../common' + +type TTableRaw = { + topic: Topic + onClick: (event: React.MouseEvent, refId: string) => void + onSearch: (search: string) => void + checkedStates: { [refId: string]: boolean } + setCheckedStates: React.Dispatch> + isMuteDisabled?: boolean +} + +interface CheckboxIconProps { + checked?: boolean +} + +const TableRowComponent: FC = ({ + topic, + onClick, + onSearch, + checkedStates, + setCheckedStates, + isMuteDisabled, +}) => { + const [ids, total] = useTopicsStore((s) => [s.ids, s.total]) + const [loading, setLoading] = useState(false) + const [isPopoverOpen, setIsPopoverOpen] = useState(false) + + const date = formatDate(topic.date_added_to_graph) + + const handleMute = async (refId: string, shouldMute: boolean) => { + setLoading(true) + + try { + await putNodeData(refId, { + node_type: topic?.node_type, + properties: { is_muted: shouldMute } + }) + + useTopicsStore.setState({ + ids: ids.filter((i) => i !== refId), + total: total - 1, + }) + } catch (error) { + console.warn(error) + } + } + + const handleSelect = (refId: string) => { + setCheckedStates((prev) => ({ + ...prev, + [refId]: !prev[refId], + })) + } + + const handleClickTopic = (event: React.MouseEvent, topicItem: Topic) => { + if (window.getSelection()?.toString()) { + event.preventDefault() + } else { + onSearch(topicItem.name) + } + } + + const lettersToShow = topic.edgeList.slice(0, 1) + const hiddenLettersCount = topic.edgeList.length - lettersToShow.length + + const [anchorEl, setAnchorEl] = React.useState(null) + + const handlePopoverOpen = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget) + setIsPopoverOpen(true) + } + + const handlePopoverClose = () => { + setIsPopoverOpen(false) + } + + const open = Boolean(anchorEl) && isPopoverOpen + + const checkboxVisibleClass = checkedStates[topic.ref_id] ? 'visible' : '' + + return ( + + + handleSelect(topic.ref_id)} + > + + {checkedStates[topic.ref_id] && } + + + + handleClickTopic(event, topic)}> + {topic.name} + + {topic.node_type} + + {topic.edgeCount} + + + setIsPopoverOpen(true)} + onMouseLeave={handlePopoverClose} + open={open} + sx={{ + pointerEvents: 'auto', + '& .MuiPaper-root': { + backgroundColor: 'rgba(0, 0, 0, 0.9)', + borderRadius: '4px', + width: '160px', + maxHeight: '200px', + overflowY: 'scroll', + }, + }} + transformOrigin={{ + vertical: 'bottom', + horizontal: 'center', + }} + > + + {topic.edgeList.join(', ')} + + + {lettersToShow.join(', ')} + {hiddenLettersCount > 0 && ( + + ,... + + )} + + + {date} + + + + +
+ {loading ? ( + + + + ) : ( + + {topic.is_muted ? ( + handleMute(topic.ref_id, false)} + > + + + ) : ( + handleMute(topic.ref_id, true)} + > + + + )} + ) => onClick(e, topic.ref_id)}> + + + + )} +
+
+
+
+ ) +} + +const ClipLoaderWrapper = styled.span` + margin-left: 12px; +` + +const ClickableText = styled.span` + cursor: pointer; + :hover { + text-decoration: underline; + } +` + +const CheckboxSection = styled.td` + visibility: hidden; + cursor: pointer; + display: flex; + align-items: center; + + &.visible { + visibility: visible; + } +` + +const CheckboxIcon = styled.div` + width: 14px; + height: 14px; + border-radius: 4px; + border: ${({ checked }) => (checked ? '#618AFF' : '2px solid #CCCCCC')}; + background-color: ${({ checked }) => (checked ? '#618AFF' : 'transparent')}; + display: flex; + justify-content: center; + align-items: center; + margin-left: 12px; +` + +const Checkmark = styled.div` + display: flex; + align-items: center; + justify-content: center; + border-radius: 2px; + background-color: transparent; +` + +const CountEdgeWrapper = styled.span` + display: flex; + align-items: center; + justify-content: center; +` + +export const TopicRow = memo(TableRowComponent) diff --git a/src/components/SourcesTableModal/SourcesView/Topics/index.tsx b/src/components/SourcesTableModal/SourcesView/Topics/index.tsx index be34b9eed..5e1b20dea 100644 --- a/src/components/SourcesTableModal/SourcesView/Topics/index.tsx +++ b/src/components/SourcesTableModal/SourcesView/Topics/index.tsx @@ -85,7 +85,10 @@ export const TopicSources = () => { const handleMute = async (refId: string, action: string) => { try { - await putNodeData(refId, { node_data: { is_muted: action === 'mute' } }) + await putNodeData(refId, { + properties: { is_muted: action === 'mute' } + }) + useTopicsStore.setState({ ids: ids.filter((i) => i !== refId), total: total - 1 }) } catch (error) { console.warn(error)