@ -1,17 +1,28 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useFindManyObjects } from '@/metadata/hooks/useFindManyObjects';
|
||||
import { Tag } from '@/ui/display/tag/components/Tag';
|
||||
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
||||
import { FieldDisplay } from '@/ui/object/field/components/FieldDisplay';
|
||||
import { FieldContext } from '@/ui/object/field/contexts/FieldContext';
|
||||
import { entityFieldsFamilySelector } from '@/ui/object/field/states/selectors/entityFieldsFamilySelector';
|
||||
import { assertNotNull } from '~/utils/assert';
|
||||
|
||||
type SettingsObjectFieldPreviewProps = {
|
||||
objectIconKey: string;
|
||||
objectLabelPlural: string;
|
||||
isObjectCustom: boolean;
|
||||
fieldIconKey: string;
|
||||
import { dataTypes } from '../constants/dataTypes';
|
||||
import { MetadataFieldDataType } from '../types/ObjectFieldDataType';
|
||||
|
||||
export type SettingsObjectFieldPreviewProps = {
|
||||
fieldIconKey?: string | null;
|
||||
fieldLabel: string;
|
||||
fieldValue: ReactNode;
|
||||
fieldName?: string;
|
||||
fieldType: MetadataFieldDataType;
|
||||
isObjectCustom: boolean;
|
||||
objectIconKey?: string | null;
|
||||
objectLabelPlural: string;
|
||||
objectNamePlural: string;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -27,6 +38,7 @@ const StyledContainer = styled.div`
|
||||
const StyledObjectSummary = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
justify-content: space-between;
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
@ -47,7 +59,7 @@ const StyledFieldPreview = styled.div`
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
height: ${({ theme }) => theme.spacing(8)};
|
||||
overflow: hidden;
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
padding: 0 ${({ theme }) => theme.spacing(2)};
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
@ -59,16 +71,38 @@ const StyledFieldLabel = styled.div`
|
||||
`;
|
||||
|
||||
export const SettingsObjectFieldPreview = ({
|
||||
objectIconKey,
|
||||
objectLabelPlural,
|
||||
isObjectCustom,
|
||||
fieldIconKey,
|
||||
fieldLabel,
|
||||
fieldValue,
|
||||
fieldName,
|
||||
fieldType,
|
||||
isObjectCustom,
|
||||
objectIconKey,
|
||||
objectLabelPlural,
|
||||
objectNamePlural,
|
||||
}: SettingsObjectFieldPreviewProps) => {
|
||||
const theme = useTheme();
|
||||
const { Icon: ObjectIcon } = useLazyLoadIcon(objectIconKey);
|
||||
const { Icon: FieldIcon } = useLazyLoadIcon(fieldIconKey);
|
||||
const { Icon: ObjectIcon } = useLazyLoadIcon(objectIconKey ?? '');
|
||||
const { Icon: FieldIcon } = useLazyLoadIcon(fieldIconKey ?? '');
|
||||
|
||||
const { objects } = useFindManyObjects({
|
||||
objectNamePlural,
|
||||
skip: !fieldName,
|
||||
});
|
||||
|
||||
const [fieldValue, setFieldValue] = useRecoilState(
|
||||
entityFieldsFamilySelector({
|
||||
entityId: objects[0]?.id ?? objectNamePlural,
|
||||
fieldName: fieldName || 'new-field',
|
||||
}),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setFieldValue(
|
||||
fieldName && assertNotNull(objects[0]?.[fieldName])
|
||||
? objects[0][fieldName]
|
||||
: dataTypes[fieldType].defaultValue,
|
||||
);
|
||||
}, [fieldName, fieldType, fieldValue, objects, setFieldValue]);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
@ -98,7 +132,21 @@ export const SettingsObjectFieldPreview = ({
|
||||
)}
|
||||
{fieldLabel}:
|
||||
</StyledFieldLabel>
|
||||
{fieldValue}
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: objects[0]?.id ?? objectNamePlural,
|
||||
fieldDefinition: {
|
||||
type: fieldType,
|
||||
Icon: FieldIcon,
|
||||
fieldId: '',
|
||||
label: fieldLabel,
|
||||
metadata: { fieldName: fieldName || 'new-field' },
|
||||
},
|
||||
hotkeyScope: 'field-preview',
|
||||
}}
|
||||
>
|
||||
<FieldDisplay />
|
||||
</FieldContext.Provider>
|
||||
</StyledFieldPreview>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { ReactNode } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
type SettingsObjectFieldPreviewCardProps = {
|
||||
type SettingsObjectFieldTypeCardProps = {
|
||||
className?: string;
|
||||
preview: ReactNode;
|
||||
form?: ReactNode;
|
||||
};
|
||||
@ -36,12 +37,13 @@ const StyledFormContainer = styled.div`
|
||||
padding: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
export const SettingsObjectFieldPreviewCard = ({
|
||||
export const SettingsObjectFieldTypeCard = ({
|
||||
className,
|
||||
preview,
|
||||
form,
|
||||
}: SettingsObjectFieldPreviewCardProps) => {
|
||||
}: SettingsObjectFieldTypeCardProps) => {
|
||||
return (
|
||||
<div>
|
||||
<div className={className}>
|
||||
<StyledPreviewContainer>
|
||||
<StyledTitle>Preview</StyledTitle>
|
||||
{preview}
|
||||
@ -1,3 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
@ -5,19 +7,45 @@ import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { dataTypes } from '../constants/dataTypes';
|
||||
import { MetadataFieldDataType } from '../types/ObjectFieldDataType';
|
||||
|
||||
import {
|
||||
SettingsObjectFieldPreview,
|
||||
SettingsObjectFieldPreviewProps,
|
||||
} from './SettingsObjectFieldPreview';
|
||||
import { SettingsObjectFieldTypeCard } from './SettingsObjectFieldTypeCard';
|
||||
|
||||
type SettingsObjectFieldTypeSelectSectionProps = {
|
||||
disabled?: boolean;
|
||||
onChange?: (value: MetadataFieldDataType) => void;
|
||||
type: MetadataFieldDataType;
|
||||
};
|
||||
} & Pick<
|
||||
SettingsObjectFieldPreviewProps,
|
||||
| 'fieldIconKey'
|
||||
| 'fieldLabel'
|
||||
| 'fieldName'
|
||||
| 'fieldType'
|
||||
| 'isObjectCustom'
|
||||
| 'objectIconKey'
|
||||
| 'objectLabelPlural'
|
||||
| 'objectNamePlural'
|
||||
>;
|
||||
|
||||
const StyledSettingsObjectFieldTypeCard = styled(SettingsObjectFieldTypeCard)`
|
||||
margin-top: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
// TODO: remove "relation" type for now, add it back when the backend is ready.
|
||||
const { RELATION: _, ...dataTypesWithoutRelation } = dataTypes;
|
||||
|
||||
export const SettingsObjectFieldTypeSelectSection = ({
|
||||
disabled,
|
||||
fieldIconKey,
|
||||
fieldLabel,
|
||||
fieldName,
|
||||
fieldType,
|
||||
isObjectCustom,
|
||||
objectIconKey,
|
||||
objectLabelPlural,
|
||||
objectNamePlural,
|
||||
onChange,
|
||||
type,
|
||||
}: SettingsObjectFieldTypeSelectSectionProps) => (
|
||||
<Section>
|
||||
<H2Title
|
||||
@ -27,7 +55,7 @@ export const SettingsObjectFieldTypeSelectSection = ({
|
||||
<Select
|
||||
disabled={disabled}
|
||||
dropdownScopeId="object-field-type-select"
|
||||
value={type}
|
||||
value={fieldType}
|
||||
onChange={onChange}
|
||||
options={Object.entries(dataTypesWithoutRelation).map(
|
||||
([key, dataType]) => ({
|
||||
@ -36,5 +64,21 @@ export const SettingsObjectFieldTypeSelectSection = ({
|
||||
}),
|
||||
)}
|
||||
/>
|
||||
{fieldType === 'TEXT' && (
|
||||
<StyledSettingsObjectFieldTypeCard
|
||||
preview={
|
||||
<SettingsObjectFieldPreview
|
||||
fieldIconKey={fieldIconKey}
|
||||
fieldLabel={fieldLabel}
|
||||
fieldName={fieldName}
|
||||
fieldType={fieldType}
|
||||
isObjectCustom={isObjectCustom}
|
||||
objectIconKey={objectIconKey}
|
||||
objectLabelPlural={objectLabelPlural}
|
||||
objectNamePlural={objectNamePlural}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
|
||||
@ -9,12 +9,12 @@ const meta: Meta<typeof SettingsObjectFieldPreview> = {
|
||||
component: SettingsObjectFieldPreview,
|
||||
decorators: [ComponentDecorator],
|
||||
args: {
|
||||
objectIconKey: 'IconUser',
|
||||
objectLabelPlural: 'People',
|
||||
fieldIconKey: 'IconNotes',
|
||||
fieldLabel: 'Description',
|
||||
fieldValue:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum magna enim, dapibus non enim in, lacinia faucibus nunc. Sed interdum ante sed felis facilisis, eget ultricies neque molestie. Mauris auctor, justo eu volutpat cursus, libero erat tempus nulla, non sodales lorem lacus a est.',
|
||||
fieldType: 'TEXT',
|
||||
objectIconKey: 'IconUser',
|
||||
objectLabelPlural: 'People',
|
||||
objectNamePlural: 'people',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -4,28 +4,29 @@ import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { SettingsObjectFieldPreview } from '../SettingsObjectFieldPreview';
|
||||
import { SettingsObjectFieldPreviewCard } from '../SettingsObjectFieldPreviewCard';
|
||||
import { SettingsObjectFieldTypeCard } from '../SettingsObjectFieldTypeCard';
|
||||
|
||||
const meta: Meta<typeof SettingsObjectFieldPreviewCard> = {
|
||||
title: 'Modules/Settings/DataModel/SettingsObjectFieldPreviewCard',
|
||||
component: SettingsObjectFieldPreviewCard,
|
||||
const meta: Meta<typeof SettingsObjectFieldTypeCard> = {
|
||||
title: 'Modules/Settings/DataModel/SettingsObjectFieldTypeCard',
|
||||
component: SettingsObjectFieldTypeCard,
|
||||
decorators: [ComponentDecorator],
|
||||
args: {
|
||||
preview: (
|
||||
<SettingsObjectFieldPreview
|
||||
objectIconKey="IconUser"
|
||||
objectLabelPlural="People"
|
||||
isObjectCustom={false}
|
||||
fieldIconKey="IconNotes"
|
||||
fieldLabel="Description"
|
||||
fieldValue="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum magna enim, dapibus non enim in, lacinia faucibus nunc. Sed interdum ante sed felis facilisis, eget ultricies neque molestie. Mauris auctor, justo eu volutpat cursus, libero erat tempus nulla, non sodales lorem lacus a est."
|
||||
fieldType="TEXT"
|
||||
isObjectCustom={false}
|
||||
objectIconKey="IconUser"
|
||||
objectLabelPlural="People"
|
||||
objectNamePlural="people"
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof SettingsObjectFieldPreviewCard>;
|
||||
type Story = StoryObj<typeof SettingsObjectFieldTypeCard>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
@ -9,7 +9,7 @@ const meta: Meta<typeof SettingsObjectFieldTypeSelectSection> = {
|
||||
title: 'Modules/Settings/DataModel/SettingsObjectFieldTypeSelectSection',
|
||||
component: SettingsObjectFieldTypeSelectSection,
|
||||
decorators: [ComponentDecorator],
|
||||
args: { type: 'NUMBER' },
|
||||
args: { fieldType: 'NUMBER' },
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
Reference in New Issue
Block a user