diff --git a/front/src/modules/settings/objects/components/ObjectFieldDataType.tsx b/front/src/modules/settings/objects/components/ObjectFieldDataType.tsx new file mode 100644 index 000000000..ffdc9009e --- /dev/null +++ b/front/src/modules/settings/objects/components/ObjectFieldDataType.tsx @@ -0,0 +1,61 @@ +import { css, useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +import { + IconCheck, + IconLink, + IconNumbers, + IconPlug, + IconSocial, + IconUserCircle, +} from '@/ui/icon'; +import { IconComponent } from '@/ui/icon/types/IconComponent'; + +import { ObjectFieldItem } from '../types/ObjectFieldItem'; + +type ObjectFieldDataTypeProps = { + value: ObjectFieldItem['dataType']; +}; + +const StyledDataType = styled.div<{ value: ObjectFieldItem['dataType'] }>` + align-items: center; + border: 1px solid transparent; + border-radius: ${({ theme }) => theme.border.radius.sm}; + display: flex; + font-size: ${({ theme }) => theme.font.size.sm}; + gap: ${({ theme }) => theme.spacing(1)}; + height: 20px; + padding: 0 ${({ theme }) => theme.spacing(2)}; + + ${({ theme, value }) => + value === 'relation' + ? css` + border-color: ${theme.color.purple20}; + color: ${theme.color.purple}; + ` + : ''} +`; + +const dataTypes: Record< + ObjectFieldItem['dataType'], + { label: string; Icon: IconComponent } +> = { + boolean: { label: 'True/False', Icon: IconCheck }, + number: { label: 'Number', Icon: IconNumbers }, + relation: { label: 'Relation', Icon: IconPlug }, + social: { label: 'Social', Icon: IconSocial }, + teammate: { label: 'Teammate', Icon: IconUserCircle }, + text: { label: 'Text', Icon: IconLink }, +}; + +export const ObjectFieldDataType = ({ value }: ObjectFieldDataTypeProps) => { + const theme = useTheme(); + const { label, Icon } = dataTypes[value]; + + return ( + + + {label} + + ); +}; diff --git a/front/src/modules/settings/objects/components/ObjectFieldItemTableRow.tsx b/front/src/modules/settings/objects/components/ObjectFieldItemTableRow.tsx new file mode 100644 index 000000000..6652e8294 --- /dev/null +++ b/front/src/modules/settings/objects/components/ObjectFieldItemTableRow.tsx @@ -0,0 +1,57 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +import { IconDotsVertical } from '@/ui/icon'; +import { TableCell } from '@/ui/table/components/TableCell'; +import { TableRow } from '@/ui/table/components/TableRow'; + +import { ObjectFieldItem } from '../types/ObjectFieldItem'; + +import { ObjectFieldDataType } from './ObjectFieldDataType'; + +export const StyledObjectFieldTableRow = styled(TableRow)` + grid-template-columns: 180px 148px 148px 36px; +`; + +const StyledNameTableCell = styled(TableCell)` + color: ${({ theme }) => theme.font.color.primary}; + gap: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledIconTableCell = styled(TableCell)` + justify-content: center; + padding-right: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledIconDotsVertical = styled(IconDotsVertical)` + color: ${({ theme }) => theme.font.color.tertiary}; +`; + +export const ObjectFieldItemTableRow = ({ + fieldItem, +}: { + fieldItem: ObjectFieldItem; +}) => { + const theme = useTheme(); + + return ( + + + + {fieldItem.name} + + + {fieldItem.type === 'standard' ? 'Standard' : 'Custom'} + + + + + + + + + ); +}; diff --git a/front/src/modules/settings/objects/constants/mockObjects.ts b/front/src/modules/settings/objects/constants/mockObjects.ts new file mode 100644 index 000000000..011fcdf5f --- /dev/null +++ b/front/src/modules/settings/objects/constants/mockObjects.ts @@ -0,0 +1,125 @@ +import { ObjectFieldItem } from '@/settings/objects/types/ObjectFieldItem'; +import { + IconBrandLinkedin, + IconBrandTwitter, + IconBuildingSkyscraper, + IconCurrencyDollar, + IconFreeRights, + IconGraph, + IconHeadphones, + IconLink, + IconLuggage, + IconPlane, + IconTarget, + IconUser, + IconUserCircle, + IconUsers, +} from '@/ui/icon'; + +export const activeObjectItems = [ + { + name: 'Companies', + singularName: 'company', + Icon: IconBuildingSkyscraper, + type: 'standard', + fields: 23, + instances: 165, + }, + { + name: 'People', + singularName: 'person', + Icon: IconUser, + type: 'standard', + fields: 16, + instances: 462, + }, +]; + +export const disabledObjectItems = [ + { + name: 'Travels', + Icon: IconLuggage, + type: 'custom', + fields: 23, + instances: 165, + }, + { + name: 'Flights', + Icon: IconPlane, + type: 'custom', + fields: 23, + instances: 165, + }, +]; + +export const activeFieldItems: ObjectFieldItem[] = [ + { + name: 'People', + Icon: IconUser, + type: 'standard', + dataType: 'relation', + }, + { + name: 'URL', + Icon: IconLink, + type: 'standard', + dataType: 'text', + }, + { + name: 'Linkedin', + Icon: IconBrandLinkedin, + type: 'standard', + dataType: 'social', + }, + { + name: 'Account Owner', + Icon: IconUserCircle, + type: 'standard', + dataType: 'teammate', + }, + { + name: 'Employees', + Icon: IconUsers, + type: 'custom', + dataType: 'number', + }, +]; + +export const disabledFieldItems: ObjectFieldItem[] = [ + { + name: 'ICP', + Icon: IconTarget, + type: 'standard', + dataType: 'boolean', + }, + { + name: 'Twitter', + Icon: IconBrandTwitter, + type: 'standard', + dataType: 'social', + }, + { + name: 'Annual revenue', + Icon: IconCurrencyDollar, + type: 'standard', + dataType: 'number', + }, + { + name: 'Is public', + Icon: IconGraph, + type: 'standard', + dataType: 'boolean', + }, + { + name: 'Free tier?', + Icon: IconFreeRights, + type: 'custom', + dataType: 'boolean', + }, + { + name: 'Priority support', + Icon: IconHeadphones, + type: 'custom', + dataType: 'boolean', + }, +]; diff --git a/front/src/pages/settings/constants/objectSettings.ts b/front/src/modules/settings/objects/constants/objectSettings.ts similarity index 100% rename from front/src/pages/settings/constants/objectSettings.ts rename to front/src/modules/settings/objects/constants/objectSettings.ts diff --git a/front/src/modules/settings/objects/types/ObjectFieldItem.ts b/front/src/modules/settings/objects/types/ObjectFieldItem.ts new file mode 100644 index 000000000..8feb6bc01 --- /dev/null +++ b/front/src/modules/settings/objects/types/ObjectFieldItem.ts @@ -0,0 +1,8 @@ +import { IconComponent } from '@/ui/icon/types/IconComponent'; + +export type ObjectFieldItem = { + name: string; + Icon: IconComponent; + type: 'standard' | 'custom'; + dataType: 'boolean' | 'number' | 'relation' | 'social' | 'teammate' | 'text'; +}; diff --git a/front/src/modules/ui/icon/index.ts b/front/src/modules/ui/icon/index.ts index d3ed9770f..eab74695b 100644 --- a/front/src/modules/ui/icon/index.ts +++ b/front/src/modules/ui/icon/index.ts @@ -40,7 +40,10 @@ export { IconFileImport, IconFileUpload, IconForbid, + IconFreeRights, + IconGraph, IconGripVertical, + IconHeadphones, IconHeart, IconHeartOff, IconHelpCircle, @@ -60,13 +63,16 @@ export { IconMinus, IconMoneybag, IconNotes, + IconNumbers, IconPencil, IconPhone, IconPlane, + IconPlug, IconPlus, IconProgressCheck, IconSearch, IconSettings, + IconSocial, IconTag, IconTarget, IconTargetArrow, diff --git a/front/src/modules/ui/layout/components/PagePanel.tsx b/front/src/modules/ui/layout/components/PagePanel.tsx index eeed1de6f..433e67671 100644 --- a/front/src/modules/ui/layout/components/PagePanel.tsx +++ b/front/src/modules/ui/layout/components/PagePanel.tsx @@ -8,6 +8,7 @@ const StyledPanel = styled.div` display: flex; flex-direction: row; height: 100%; + overflow: auto; width: 100%; `; diff --git a/front/src/modules/ui/table/components/TableSection.tsx b/front/src/modules/ui/table/components/TableSection.tsx index 83132bc73..6e799514b 100644 --- a/front/src/modules/ui/table/components/TableSection.tsx +++ b/front/src/modules/ui/table/components/TableSection.tsx @@ -6,6 +6,7 @@ import { IconChevronDown, IconChevronUp } from '@/ui/icon'; type TableSectionProps = { children: ReactNode; + isInitiallyExpanded?: boolean; title: string; }; @@ -38,9 +39,13 @@ const StyledSectionContent = styled.div` padding: ${({ theme }) => theme.spacing(2)} 0; `; -export const TableSection = ({ children, title }: TableSectionProps) => { +export const TableSection = ({ + children, + isInitiallyExpanded = true, + title, +}: TableSectionProps) => { const theme = useTheme(); - const [isExpanded, setIsExpanded] = useState(true); + const [isExpanded, setIsExpanded] = useState(isInitiallyExpanded); const handleToggleSection = () => setIsExpanded((previousIsExpanded) => !previousIsExpanded); diff --git a/front/src/pages/settings/SettingsNewObject.tsx b/front/src/pages/settings/SettingsNewObject.tsx index 0aafd73ff..e1513c4a0 100644 --- a/front/src/pages/settings/SettingsNewObject.tsx +++ b/front/src/pages/settings/SettingsNewObject.tsx @@ -1,12 +1,12 @@ import styled from '@emotion/styled'; +import { objectSettingsWidth } from '@/settings/objects/constants/objectSettings'; import { Breadcrumb } from '@/ui/breadcrumb/components/Breadcrumb'; import { IconSettings } from '@/ui/icon'; import { SubMenuTopBarContainer } from '@/ui/layout/components/SubMenuTopBarContainer'; -import { objectSettingsWidth } from './constants/objectSettings'; - const StyledContainer = styled.div` + height: fit-content; padding: ${({ theme }) => theme.spacing(8)}; width: ${objectSettingsWidth}; `; diff --git a/front/src/pages/settings/SettingsObjectDetail.tsx b/front/src/pages/settings/SettingsObjectDetail.tsx index 8ed4a33d9..e635beb22 100644 --- a/front/src/pages/settings/SettingsObjectDetail.tsx +++ b/front/src/pages/settings/SettingsObjectDetail.tsx @@ -2,19 +2,43 @@ import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; +import { + ObjectFieldItemTableRow, + StyledObjectFieldTableRow, +} from '@/settings/objects/components/ObjectFieldItemTableRow'; +import { + activeFieldItems, + activeObjectItems, + disabledFieldItems, +} from '@/settings/objects/constants/mockObjects'; +import { objectSettingsWidth } from '@/settings/objects/constants/objectSettings'; import { AppPath } from '@/types/AppPath'; import { Breadcrumb } from '@/ui/breadcrumb/components/Breadcrumb'; -import { IconSettings } from '@/ui/icon'; +import { Button } from '@/ui/button/components/Button'; +import { IconPlus, IconSettings } from '@/ui/icon'; import { SubMenuTopBarContainer } from '@/ui/layout/components/SubMenuTopBarContainer'; - -import { activeObjectItems } from './constants/mockObjects'; -import { objectSettingsWidth } from './constants/objectSettings'; +import { Table } from '@/ui/table/components/Table'; +import { TableHeader } from '@/ui/table/components/TableHeader'; +import { TableSection } from '@/ui/table/components/TableSection'; +import { H2Title } from '@/ui/typography/components/H2Title'; const StyledContainer = styled.div` + display: flex; + flex-direction: column; + height: fit-content; padding: ${({ theme }) => theme.spacing(8)}; width: ${objectSettingsWidth}; `; +const StyledBreadcrumb = styled(Breadcrumb)` + margin-bottom: ${({ theme }) => theme.spacing(8)}; +`; + +const StyledAddFieldButton = styled(Button)` + align-self: flex-end; + margin-top: ${({ theme }) => theme.spacing(2)}; +`; + export const SettingsObjectDetail = () => { const navigate = useNavigate(); const { pluralObjectName = '' } = useParams(); @@ -29,12 +53,48 @@ export const SettingsObjectDetail = () => { return ( - + + + + Name + Field type + Data type + + + + {activeFieldItems.map((fieldItem) => ( + + ))} + + {!!disabledFieldItems.length && ( + + {disabledFieldItems.map((fieldItem) => ( + + ))} + + )} +
+
); diff --git a/front/src/pages/settings/SettingsObjectEdit.tsx b/front/src/pages/settings/SettingsObjectEdit.tsx index e07b6896b..a0740143b 100644 --- a/front/src/pages/settings/SettingsObjectEdit.tsx +++ b/front/src/pages/settings/SettingsObjectEdit.tsx @@ -2,15 +2,15 @@ import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; +import { activeObjectItems } from '@/settings/objects/constants/mockObjects'; +import { objectSettingsWidth } from '@/settings/objects/constants/objectSettings'; import { AppPath } from '@/types/AppPath'; import { Breadcrumb } from '@/ui/breadcrumb/components/Breadcrumb'; import { IconSettings } from '@/ui/icon'; import { SubMenuTopBarContainer } from '@/ui/layout/components/SubMenuTopBarContainer'; -import { activeObjectItems } from './constants/mockObjects'; -import { objectSettingsWidth } from './constants/objectSettings'; - const StyledContainer = styled.div` + height: fit-content; padding: ${({ theme }) => theme.spacing(8)}; width: ${objectSettingsWidth}; `; diff --git a/front/src/pages/settings/SettingsObjects.tsx b/front/src/pages/settings/SettingsObjects.tsx index d54584646..16221c10b 100644 --- a/front/src/pages/settings/SettingsObjects.tsx +++ b/front/src/pages/settings/SettingsObjects.tsx @@ -2,6 +2,11 @@ import { useNavigate } from 'react-router-dom'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { + activeObjectItems, + disabledObjectItems, +} from '@/settings/objects/constants/mockObjects'; +import { objectSettingsWidth } from '@/settings/objects/constants/objectSettings'; import { Button } from '@/ui/button/components/Button'; import { IconChevronRight, @@ -19,13 +24,8 @@ import { Tag } from '@/ui/tag/components/Tag'; import { H1Title } from '@/ui/typography/components/H1Title'; import { H2Title } from '@/ui/typography/components/H2Title'; -import { - activeObjectItems, - disabledObjectItems, -} from './constants/mockObjects'; -import { objectSettingsWidth } from './constants/objectSettings'; - const StyledContainer = styled.div` + height: fit-content; padding: ${({ theme }) => theme.spacing(8)}; width: ${objectSettingsWidth}; `; diff --git a/front/src/pages/settings/SettingsWorkspaceMembers.tsx b/front/src/pages/settings/SettingsWorkspaceMembers.tsx index 7593ee833..6ef7ccfe3 100644 --- a/front/src/pages/settings/SettingsWorkspaceMembers.tsx +++ b/front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -20,6 +20,7 @@ import { const StyledContainer = styled.div` display: flex; flex-direction: column; + height: fit-content; padding: ${({ theme }) => theme.spacing(8)}; width: 350px; `; diff --git a/front/src/pages/settings/constants/mockObjects.ts b/front/src/pages/settings/constants/mockObjects.ts deleted file mode 100644 index 2639cc17f..000000000 --- a/front/src/pages/settings/constants/mockObjects.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - IconBuildingSkyscraper, - IconLuggage, - IconPlane, - IconUser, -} from '@/ui/icon'; - -export const activeObjectItems = [ - { - name: 'Companies', - Icon: IconBuildingSkyscraper, - type: 'standard', - fields: 23, - instances: 165, - }, - { - name: 'People', - Icon: IconUser, - type: 'standard', - fields: 16, - instances: 462, - }, -]; - -export const disabledObjectItems = [ - { - name: 'Travels', - Icon: IconLuggage, - type: 'custom', - fields: 23, - instances: 165, - }, - { - name: 'Flights', - Icon: IconPlane, - type: 'custom', - fields: 23, - instances: 165, - }, -];